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