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.NetworkStats.DEFAULT_NETWORK_ALL; 27 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 28 import static android.net.NetworkStats.DEFAULT_NETWORK_YES; 29 import static android.net.NetworkStats.METERED_ALL; 30 import static android.net.NetworkStats.METERED_NO; 31 import static android.net.NetworkStats.METERED_YES; 32 import static android.net.NetworkStats.ROAMING_ALL; 33 import static android.net.NetworkStats.ROAMING_NO; 34 import static android.net.NetworkStats.ROAMING_YES; 35 import static android.net.wifi.WifiInfo.sanitizeSsid; 36 37 import android.annotation.NonNull; 38 import android.annotation.Nullable; 39 import android.compat.annotation.UnsupportedAppUsage; 40 import android.os.Parcel; 41 import android.os.Parcelable; 42 import android.telephony.Annotation.NetworkType; 43 import android.telephony.TelephonyManager; 44 import android.text.TextUtils; 45 import android.util.BackupUtils; 46 import android.util.Log; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.internal.util.ArrayUtils; 50 51 import java.io.ByteArrayOutputStream; 52 import java.io.DataInputStream; 53 import java.io.DataOutputStream; 54 import java.io.IOException; 55 import java.util.Arrays; 56 import java.util.Collection; 57 import java.util.HashSet; 58 import java.util.List; 59 import java.util.Objects; 60 61 /** 62 * Predicate used to match {@link NetworkIdentity}, usually when collecting 63 * statistics. (It should probably have been named {@code NetworkPredicate}.) 64 * 65 * @hide 66 */ 67 public class NetworkTemplate implements Parcelable { 68 private static final String TAG = "NetworkTemplate"; 69 70 /** 71 * Current Version of the Backup Serializer. 72 */ 73 private static final int BACKUP_VERSION = 1; 74 75 public static final int MATCH_MOBILE = 1; 76 public static final int MATCH_WIFI = 4; 77 public static final int MATCH_ETHERNET = 5; 78 public static final int MATCH_MOBILE_WILDCARD = 6; 79 public static final int MATCH_WIFI_WILDCARD = 7; 80 public static final int MATCH_BLUETOOTH = 8; 81 public static final int MATCH_PROXY = 9; 82 83 /** 84 * Include all network types when filtering. This is meant to merge in with the 85 * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. 86 * 87 * @hide 88 */ 89 public static final int NETWORK_TYPE_ALL = -1; 90 /** 91 * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is 92 * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along 93 * with NR state as connected. This should not be overlapped with any of the 94 * {@code TelephonyManager.NETWORK_TYPE_*} constants. 95 * 96 * @hide 97 */ 98 public static final int NETWORK_TYPE_5G_NSA = -2; 99 isKnownMatchRule(final int rule)100 private static boolean isKnownMatchRule(final int rule) { 101 switch (rule) { 102 case MATCH_MOBILE: 103 case MATCH_WIFI: 104 case MATCH_ETHERNET: 105 case MATCH_MOBILE_WILDCARD: 106 case MATCH_WIFI_WILDCARD: 107 case MATCH_BLUETOOTH: 108 case MATCH_PROXY: 109 return true; 110 111 default: 112 return false; 113 } 114 } 115 116 private static boolean sForceAllNetworkTypes = false; 117 118 /** 119 * Results in matching against all mobile network types. 120 * 121 * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}. 122 */ 123 @VisibleForTesting forceAllNetworkTypes()124 public static void forceAllNetworkTypes() { 125 sForceAllNetworkTypes = true; 126 } 127 128 /** Resets the affect of {@link #forceAllNetworkTypes}. */ 129 @VisibleForTesting resetForceAllNetworkTypes()130 public static void resetForceAllNetworkTypes() { 131 sForceAllNetworkTypes = false; 132 } 133 134 /** 135 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 136 * the given IMSI. 137 */ 138 @UnsupportedAppUsage buildTemplateMobileAll(String subscriberId)139 public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { 140 return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); 141 } 142 143 /** 144 * Template to match cellular networks with the given IMSI and {@code ratType}. 145 * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. 146 * See {@code TelephonyManager.NETWORK_TYPE_*}. 147 */ buildTemplateMobileWithRatType(@ullable String subscriberId, @NetworkType int ratType)148 public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, 149 @NetworkType int ratType) { 150 if (TextUtils.isEmpty(subscriberId)) { 151 return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, 152 METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); 153 } 154 return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, 155 METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); 156 } 157 158 /** 159 * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, 160 * regardless of IMSI. 161 */ 162 @UnsupportedAppUsage buildTemplateMobileWildcard()163 public static NetworkTemplate buildTemplateMobileWildcard() { 164 return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); 165 } 166 167 /** 168 * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, 169 * regardless of SSID. 170 */ 171 @UnsupportedAppUsage buildTemplateWifiWildcard()172 public static NetworkTemplate buildTemplateWifiWildcard() { 173 return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); 174 } 175 176 @Deprecated 177 @UnsupportedAppUsage buildTemplateWifi()178 public static NetworkTemplate buildTemplateWifi() { 179 return buildTemplateWifiWildcard(); 180 } 181 182 /** 183 * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the 184 * given SSID. 185 */ buildTemplateWifi(String networkId)186 public static NetworkTemplate buildTemplateWifi(String networkId) { 187 return new NetworkTemplate(MATCH_WIFI, null, networkId); 188 } 189 190 /** 191 * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style 192 * networks together. 193 */ 194 @UnsupportedAppUsage buildTemplateEthernet()195 public static NetworkTemplate buildTemplateEthernet() { 196 return new NetworkTemplate(MATCH_ETHERNET, null, null); 197 } 198 199 /** 200 * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style 201 * networks together. 202 */ buildTemplateBluetooth()203 public static NetworkTemplate buildTemplateBluetooth() { 204 return new NetworkTemplate(MATCH_BLUETOOTH, null, null); 205 } 206 207 /** 208 * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style 209 * networks together. 210 */ buildTemplateProxy()211 public static NetworkTemplate buildTemplateProxy() { 212 return new NetworkTemplate(MATCH_PROXY, null, null); 213 } 214 215 private final int mMatchRule; 216 private final String mSubscriberId; 217 218 /** 219 * Ugh, templates are designed to target a single subscriber, but we might 220 * need to match several "merged" subscribers. These are the subscribers 221 * that should be considered to match this template. 222 * <p> 223 * Since the merge set is dynamic, it should <em>not</em> be persisted or 224 * used for determining equality. 225 */ 226 private final String[] mMatchSubscriberIds; 227 228 private final String mNetworkId; 229 230 // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. 231 private final int mMetered; 232 private final int mRoaming; 233 private final int mDefaultNetwork; 234 private final int mSubType; 235 236 @UnsupportedAppUsage NetworkTemplate(int matchRule, String subscriberId, String networkId)237 public NetworkTemplate(int matchRule, String subscriberId, String networkId) { 238 this(matchRule, subscriberId, new String[] { subscriberId }, networkId); 239 } 240 NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId)241 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 242 String networkId) { 243 this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, 244 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); 245 } 246 NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType)247 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 248 String networkId, int metered, int roaming, int defaultNetwork, int subType) { 249 mMatchRule = matchRule; 250 mSubscriberId = subscriberId; 251 mMatchSubscriberIds = matchSubscriberIds; 252 mNetworkId = networkId; 253 mMetered = metered; 254 mRoaming = roaming; 255 mDefaultNetwork = defaultNetwork; 256 mSubType = subType; 257 258 if (!isKnownMatchRule(matchRule)) { 259 Log.e(TAG, "Unknown network template rule " + matchRule 260 + " will not match any identity."); 261 } 262 } 263 NetworkTemplate(Parcel in)264 private NetworkTemplate(Parcel in) { 265 mMatchRule = in.readInt(); 266 mSubscriberId = in.readString(); 267 mMatchSubscriberIds = in.createStringArray(); 268 mNetworkId = in.readString(); 269 mMetered = in.readInt(); 270 mRoaming = in.readInt(); 271 mDefaultNetwork = in.readInt(); 272 mSubType = in.readInt(); 273 } 274 275 @Override writeToParcel(Parcel dest, int flags)276 public void writeToParcel(Parcel dest, int flags) { 277 dest.writeInt(mMatchRule); 278 dest.writeString(mSubscriberId); 279 dest.writeStringArray(mMatchSubscriberIds); 280 dest.writeString(mNetworkId); 281 dest.writeInt(mMetered); 282 dest.writeInt(mRoaming); 283 dest.writeInt(mDefaultNetwork); 284 dest.writeInt(mSubType); 285 } 286 287 @Override describeContents()288 public int describeContents() { 289 return 0; 290 } 291 292 @Override toString()293 public String toString() { 294 final StringBuilder builder = new StringBuilder("NetworkTemplate: "); 295 builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); 296 if (mSubscriberId != null) { 297 builder.append(", subscriberId=").append( 298 NetworkIdentity.scrubSubscriberId(mSubscriberId)); 299 } 300 if (mMatchSubscriberIds != null) { 301 builder.append(", matchSubscriberIds=").append( 302 Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds))); 303 } 304 if (mNetworkId != null) { 305 builder.append(", networkId=").append(mNetworkId); 306 } 307 if (mMetered != METERED_ALL) { 308 builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); 309 } 310 if (mRoaming != ROAMING_ALL) { 311 builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); 312 } 313 if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { 314 builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( 315 mDefaultNetwork)); 316 } 317 if (mSubType != NETWORK_TYPE_ALL) { 318 builder.append(", subType=").append(mSubType); 319 } 320 return builder.toString(); 321 } 322 323 @Override hashCode()324 public int hashCode() { 325 return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, 326 mDefaultNetwork, mSubType); 327 } 328 329 @Override equals(Object obj)330 public boolean equals(Object obj) { 331 if (obj instanceof NetworkTemplate) { 332 final NetworkTemplate other = (NetworkTemplate) obj; 333 return mMatchRule == other.mMatchRule 334 && Objects.equals(mSubscriberId, other.mSubscriberId) 335 && Objects.equals(mNetworkId, other.mNetworkId) 336 && mMetered == other.mMetered 337 && mRoaming == other.mRoaming 338 && mDefaultNetwork == other.mDefaultNetwork 339 && mSubType == other.mSubType; 340 } 341 return false; 342 } 343 isMatchRuleMobile()344 public boolean isMatchRuleMobile() { 345 switch (mMatchRule) { 346 case MATCH_MOBILE: 347 case MATCH_MOBILE_WILDCARD: 348 return true; 349 default: 350 return false; 351 } 352 } 353 isPersistable()354 public boolean isPersistable() { 355 switch (mMatchRule) { 356 case MATCH_MOBILE_WILDCARD: 357 case MATCH_WIFI_WILDCARD: 358 return false; 359 default: 360 return true; 361 } 362 } 363 364 @UnsupportedAppUsage getMatchRule()365 public int getMatchRule() { 366 return mMatchRule; 367 } 368 369 @UnsupportedAppUsage getSubscriberId()370 public String getSubscriberId() { 371 return mSubscriberId; 372 } 373 getNetworkId()374 public String getNetworkId() { 375 return mNetworkId; 376 } 377 378 /** 379 * Test if given {@link NetworkIdentity} matches this template. 380 */ matches(NetworkIdentity ident)381 public boolean matches(NetworkIdentity ident) { 382 if (!matchesMetered(ident)) return false; 383 if (!matchesRoaming(ident)) return false; 384 if (!matchesDefaultNetwork(ident)) return false; 385 386 switch (mMatchRule) { 387 case MATCH_MOBILE: 388 return matchesMobile(ident); 389 case MATCH_WIFI: 390 return matchesWifi(ident); 391 case MATCH_ETHERNET: 392 return matchesEthernet(ident); 393 case MATCH_MOBILE_WILDCARD: 394 return matchesMobileWildcard(ident); 395 case MATCH_WIFI_WILDCARD: 396 return matchesWifiWildcard(ident); 397 case MATCH_BLUETOOTH: 398 return matchesBluetooth(ident); 399 case MATCH_PROXY: 400 return matchesProxy(ident); 401 default: 402 // We have no idea what kind of network template we are, so we 403 // just claim not to match anything. 404 return false; 405 } 406 } 407 matchesMetered(NetworkIdentity ident)408 private boolean matchesMetered(NetworkIdentity ident) { 409 return (mMetered == METERED_ALL) 410 || (mMetered == METERED_YES && ident.mMetered) 411 || (mMetered == METERED_NO && !ident.mMetered); 412 } 413 matchesRoaming(NetworkIdentity ident)414 private boolean matchesRoaming(NetworkIdentity ident) { 415 return (mRoaming == ROAMING_ALL) 416 || (mRoaming == ROAMING_YES && ident.mRoaming) 417 || (mRoaming == ROAMING_NO && !ident.mRoaming); 418 } 419 matchesDefaultNetwork(NetworkIdentity ident)420 private boolean matchesDefaultNetwork(NetworkIdentity ident) { 421 return (mDefaultNetwork == DEFAULT_NETWORK_ALL) 422 || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) 423 || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); 424 } 425 matchesCollapsedRatType(NetworkIdentity ident)426 private boolean matchesCollapsedRatType(NetworkIdentity ident) { 427 return mSubType == NETWORK_TYPE_ALL 428 || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); 429 } 430 matchesSubscriberId(String subscriberId)431 public boolean matchesSubscriberId(String subscriberId) { 432 return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); 433 } 434 435 /** 436 * Check if mobile network with matching IMSI. 437 */ matchesMobile(NetworkIdentity ident)438 private boolean matchesMobile(NetworkIdentity ident) { 439 if (ident.mType == TYPE_WIMAX) { 440 // TODO: consider matching against WiMAX subscriber identity 441 return true; 442 } else { 443 // Only metered mobile network would be matched regardless of metered filter. 444 // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. 445 // TODO: Respect metered filter and remove mMetered condition. 446 return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) 447 && !ArrayUtils.isEmpty(mMatchSubscriberIds) 448 && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) 449 && matchesCollapsedRatType(ident); 450 } 451 } 452 453 /** 454 * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. 455 * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. 456 * 457 * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. 458 */ 459 // TODO: 1. Consider move this to TelephonyManager if used by other modules. 460 // 2. Consider make this configurable. 461 // 3. Use TelephonyManager APIs when available. getCollapsedRatType(int ratType)462 public static int getCollapsedRatType(int ratType) { 463 switch (ratType) { 464 case TelephonyManager.NETWORK_TYPE_GPRS: 465 case TelephonyManager.NETWORK_TYPE_GSM: 466 case TelephonyManager.NETWORK_TYPE_EDGE: 467 case TelephonyManager.NETWORK_TYPE_IDEN: 468 case TelephonyManager.NETWORK_TYPE_CDMA: 469 case TelephonyManager.NETWORK_TYPE_1xRTT: 470 return TelephonyManager.NETWORK_TYPE_GSM; 471 case TelephonyManager.NETWORK_TYPE_EVDO_0: 472 case TelephonyManager.NETWORK_TYPE_EVDO_A: 473 case TelephonyManager.NETWORK_TYPE_EVDO_B: 474 case TelephonyManager.NETWORK_TYPE_EHRPD: 475 case TelephonyManager.NETWORK_TYPE_UMTS: 476 case TelephonyManager.NETWORK_TYPE_HSDPA: 477 case TelephonyManager.NETWORK_TYPE_HSUPA: 478 case TelephonyManager.NETWORK_TYPE_HSPA: 479 case TelephonyManager.NETWORK_TYPE_HSPAP: 480 case TelephonyManager.NETWORK_TYPE_TD_SCDMA: 481 return TelephonyManager.NETWORK_TYPE_UMTS; 482 case TelephonyManager.NETWORK_TYPE_LTE: 483 case TelephonyManager.NETWORK_TYPE_IWLAN: 484 return TelephonyManager.NETWORK_TYPE_LTE; 485 case TelephonyManager.NETWORK_TYPE_NR: 486 return TelephonyManager.NETWORK_TYPE_NR; 487 // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. 488 case NetworkTemplate.NETWORK_TYPE_5G_NSA: 489 return NetworkTemplate.NETWORK_TYPE_5G_NSA; 490 default: 491 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 492 } 493 } 494 495 /** 496 * Return all supported collapsed RAT types that could be returned by 497 * {@link #getCollapsedRatType(int)}. 498 */ 499 @NonNull getAllCollapsedRatTypes()500 public static final int[] getAllCollapsedRatTypes() { 501 final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); 502 final HashSet<Integer> collapsedRatTypes = new HashSet<>(); 503 for (final int ratType : ratTypes) { 504 collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); 505 } 506 // Ensure that unknown type is returned. 507 collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); 508 return toIntArray(collapsedRatTypes); 509 } 510 511 @NonNull toIntArray(@onNull Collection<Integer> list)512 private static int[] toIntArray(@NonNull Collection<Integer> list) { 513 final int[] array = new int[list.size()]; 514 int i = 0; 515 for (final Integer item : list) { 516 array[i++] = item; 517 } 518 return array; 519 } 520 521 /** 522 * Check if matches Wi-Fi network template. 523 */ matchesWifi(NetworkIdentity ident)524 private boolean matchesWifi(NetworkIdentity ident) { 525 switch (ident.mType) { 526 case TYPE_WIFI: 527 return Objects.equals( 528 sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); 529 default: 530 return false; 531 } 532 } 533 534 /** 535 * Check if matches Ethernet network template. 536 */ matchesEthernet(NetworkIdentity ident)537 private boolean matchesEthernet(NetworkIdentity ident) { 538 if (ident.mType == TYPE_ETHERNET) { 539 return true; 540 } 541 return false; 542 } 543 matchesMobileWildcard(NetworkIdentity ident)544 private boolean matchesMobileWildcard(NetworkIdentity ident) { 545 if (ident.mType == TYPE_WIMAX) { 546 return true; 547 } else { 548 return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) 549 && matchesCollapsedRatType(ident); 550 } 551 } 552 matchesWifiWildcard(NetworkIdentity ident)553 private boolean matchesWifiWildcard(NetworkIdentity ident) { 554 switch (ident.mType) { 555 case TYPE_WIFI: 556 case TYPE_WIFI_P2P: 557 return true; 558 default: 559 return false; 560 } 561 } 562 563 /** 564 * Check if matches Bluetooth network template. 565 */ matchesBluetooth(NetworkIdentity ident)566 private boolean matchesBluetooth(NetworkIdentity ident) { 567 if (ident.mType == TYPE_BLUETOOTH) { 568 return true; 569 } 570 return false; 571 } 572 573 /** 574 * Check if matches Proxy network template. 575 */ matchesProxy(NetworkIdentity ident)576 private boolean matchesProxy(NetworkIdentity ident) { 577 return ident.mType == TYPE_PROXY; 578 } 579 getMatchRuleName(int matchRule)580 private static String getMatchRuleName(int matchRule) { 581 switch (matchRule) { 582 case MATCH_MOBILE: 583 return "MOBILE"; 584 case MATCH_WIFI: 585 return "WIFI"; 586 case MATCH_ETHERNET: 587 return "ETHERNET"; 588 case MATCH_MOBILE_WILDCARD: 589 return "MOBILE_WILDCARD"; 590 case MATCH_WIFI_WILDCARD: 591 return "WIFI_WILDCARD"; 592 case MATCH_BLUETOOTH: 593 return "BLUETOOTH"; 594 case MATCH_PROXY: 595 return "PROXY"; 596 default: 597 return "UNKNOWN(" + matchRule + ")"; 598 } 599 } 600 601 /** 602 * Examine the given template and normalize if it refers to a "merged" 603 * mobile subscriber. We pick the "lowest" merged subscriber as the primary 604 * for key purposes, and expand the template to match all other merged 605 * subscribers. 606 * <p> 607 * For example, given an incoming template matching B, and the currently 608 * active merge set [A,B], we'd return a new template that primarily matches 609 * A, but also matches B. 610 * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. 611 */ 612 @UnsupportedAppUsage normalize(NetworkTemplate template, String[] merged)613 public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { 614 return normalize(template, Arrays.<String[]>asList(merged)); 615 } 616 617 /** 618 * Examine the given template and normalize if it refers to a "merged" 619 * mobile subscriber. We pick the "lowest" merged subscriber as the primary 620 * for key purposes, and expand the template to match all other merged 621 * subscribers. 622 * 623 * There can be multiple merged subscriberIds for multi-SIM devices. 624 * 625 * <p> 626 * For example, given an incoming template matching B, and the currently 627 * active merge set [A,B], we'd return a new template that primarily matches 628 * A, but also matches B. 629 */ normalize(NetworkTemplate template, List<String[]> mergedList)630 public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { 631 if (!template.isMatchRuleMobile()) return template; 632 633 for (String[] merged : mergedList) { 634 if (ArrayUtils.contains(merged, template.mSubscriberId)) { 635 // Requested template subscriber is part of the merge group; return 636 // a template that matches all merged subscribers. 637 return new NetworkTemplate(template.mMatchRule, merged[0], merged, 638 template.mNetworkId); 639 } 640 } 641 642 return template; 643 } 644 645 @UnsupportedAppUsage 646 public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { 647 @Override 648 public NetworkTemplate createFromParcel(Parcel in) { 649 return new NetworkTemplate(in); 650 } 651 652 @Override 653 public NetworkTemplate[] newArray(int size) { 654 return new NetworkTemplate[size]; 655 } 656 }; 657 getBytesForBackup()658 public byte[] getBytesForBackup() throws IOException { 659 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 660 DataOutputStream out = new DataOutputStream(baos); 661 662 out.writeInt(BACKUP_VERSION); 663 664 out.writeInt(mMatchRule); 665 BackupUtils.writeString(out, mSubscriberId); 666 BackupUtils.writeString(out, mNetworkId); 667 668 return baos.toByteArray(); 669 } 670 getNetworkTemplateFromBackup(DataInputStream in)671 public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in) 672 throws IOException, BackupUtils.BadVersionException { 673 int version = in.readInt(); 674 if (version < 1 || version > BACKUP_VERSION) { 675 throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); 676 } 677 678 int matchRule = in.readInt(); 679 String subscriberId = BackupUtils.readString(in); 680 String networkId = BackupUtils.readString(in); 681 682 if (!isKnownMatchRule(matchRule)) { 683 throw new BackupUtils.BadVersionException( 684 "Restored network template contains unknown match rule " + matchRule); 685 } 686 687 return new NetworkTemplate(matchRule, subscriberId, networkId); 688 } 689 } 690