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