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