• 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.net.ConnectivityManager.TYPE_BLUETOOTH;
20 import static android.net.ConnectivityManager.TYPE_ETHERNET;
21 import static android.net.ConnectivityManager.TYPE_MOBILE;
22 import static android.net.ConnectivityManager.TYPE_PROXY;
23 import static android.net.ConnectivityManager.TYPE_WIFI;
24 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
25 import static android.net.ConnectivityManager.TYPE_WIMAX;
26 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
27 import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
28 import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
29 import static android.net.NetworkStats.METERED_ALL;
30 import static android.net.NetworkStats.METERED_NO;
31 import static android.net.NetworkStats.METERED_YES;
32 import static android.net.NetworkStats.ROAMING_ALL;
33 import static android.net.NetworkStats.ROAMING_NO;
34 import static android.net.NetworkStats.ROAMING_YES;
35 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
36 
37 import android.annotation.UnsupportedAppUsage;
38 import android.os.Parcel;
39 import android.os.Parcelable;
40 import android.util.BackupUtils;
41 import android.util.Log;
42 
43 import com.android.internal.annotations.VisibleForTesting;
44 import com.android.internal.util.ArrayUtils;
45 
46 import java.io.ByteArrayOutputStream;
47 import java.io.DataInputStream;
48 import java.io.DataOutputStream;
49 import java.io.IOException;
50 import java.util.Arrays;
51 import java.util.Objects;
52 
53 /**
54  * Predicate used to match {@link NetworkIdentity}, usually when collecting
55  * statistics. (It should probably have been named {@code NetworkPredicate}.)
56  *
57  * @hide
58  */
59 public class NetworkTemplate implements Parcelable {
60     private static final String TAG = "NetworkTemplate";
61 
62     /**
63      * Current Version of the Backup Serializer.
64      */
65     private static final int BACKUP_VERSION = 1;
66 
67     public static final int MATCH_MOBILE = 1;
68     public static final int MATCH_WIFI = 4;
69     public static final int MATCH_ETHERNET = 5;
70     public static final int MATCH_MOBILE_WILDCARD = 6;
71     public static final int MATCH_WIFI_WILDCARD = 7;
72     public static final int MATCH_BLUETOOTH = 8;
73     public static final int MATCH_PROXY = 9;
74 
isKnownMatchRule(final int rule)75     private static boolean isKnownMatchRule(final int rule) {
76         switch (rule) {
77             case MATCH_MOBILE:
78             case MATCH_WIFI:
79             case MATCH_ETHERNET:
80             case MATCH_MOBILE_WILDCARD:
81             case MATCH_WIFI_WILDCARD:
82             case MATCH_BLUETOOTH:
83             case MATCH_PROXY:
84                 return true;
85 
86             default:
87                 return false;
88         }
89     }
90 
91     private static boolean sForceAllNetworkTypes = false;
92 
93     /**
94      * Results in matching against all mobile network types.
95      *
96      * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
97      */
98     @VisibleForTesting
forceAllNetworkTypes()99     public static void forceAllNetworkTypes() {
100         sForceAllNetworkTypes = true;
101     }
102 
103     /** Resets the affect of {@link #forceAllNetworkTypes}. */
104     @VisibleForTesting
resetForceAllNetworkTypes()105     public static void resetForceAllNetworkTypes() {
106         sForceAllNetworkTypes = false;
107     }
108 
109     /**
110      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
111      * the given IMSI.
112      */
113     @UnsupportedAppUsage
buildTemplateMobileAll(String subscriberId)114     public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
115         return new NetworkTemplate(MATCH_MOBILE, subscriberId, null);
116     }
117 
118     /**
119      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
120      * regardless of IMSI.
121      */
122     @UnsupportedAppUsage
buildTemplateMobileWildcard()123     public static NetworkTemplate buildTemplateMobileWildcard() {
124         return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
125     }
126 
127     /**
128      * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
129      * regardless of SSID.
130      */
131     @UnsupportedAppUsage
buildTemplateWifiWildcard()132     public static NetworkTemplate buildTemplateWifiWildcard() {
133         return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
134     }
135 
136     @Deprecated
137     @UnsupportedAppUsage
buildTemplateWifi()138     public static NetworkTemplate buildTemplateWifi() {
139         return buildTemplateWifiWildcard();
140     }
141 
142     /**
143      * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
144      * given SSID.
145      */
buildTemplateWifi(String networkId)146     public static NetworkTemplate buildTemplateWifi(String networkId) {
147         return new NetworkTemplate(MATCH_WIFI, null, networkId);
148     }
149 
150     /**
151      * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
152      * networks together.
153      */
154     @UnsupportedAppUsage
buildTemplateEthernet()155     public static NetworkTemplate buildTemplateEthernet() {
156         return new NetworkTemplate(MATCH_ETHERNET, null, null);
157     }
158 
159     /**
160      * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
161      * networks together.
162      */
buildTemplateBluetooth()163     public static NetworkTemplate buildTemplateBluetooth() {
164         return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
165     }
166 
167     /**
168      * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style
169      * networks together.
170      */
buildTemplateProxy()171     public static NetworkTemplate buildTemplateProxy() {
172         return new NetworkTemplate(MATCH_PROXY, null, null);
173     }
174 
175     private final int mMatchRule;
176     private final String mSubscriberId;
177 
178     /**
179      * Ugh, templates are designed to target a single subscriber, but we might
180      * need to match several "merged" subscribers. These are the subscribers
181      * that should be considered to match this template.
182      * <p>
183      * Since the merge set is dynamic, it should <em>not</em> be persisted or
184      * used for determining equality.
185      */
186     private final String[] mMatchSubscriberIds;
187 
188     private final String mNetworkId;
189 
190     // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*.
191     private final int mMetered;
192     private final int mRoaming;
193     private final int mDefaultNetwork;
194 
195     @UnsupportedAppUsage
NetworkTemplate(int matchRule, String subscriberId, String networkId)196     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
197         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
198     }
199 
NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId)200     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
201             String networkId) {
202         this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
203                 DEFAULT_NETWORK_ALL);
204     }
205 
NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork)206     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
207             String networkId, int metered, int roaming, int defaultNetwork) {
208         mMatchRule = matchRule;
209         mSubscriberId = subscriberId;
210         mMatchSubscriberIds = matchSubscriberIds;
211         mNetworkId = networkId;
212         mMetered = metered;
213         mRoaming = roaming;
214         mDefaultNetwork = defaultNetwork;
215 
216         if (!isKnownMatchRule(matchRule)) {
217             Log.e(TAG, "Unknown network template rule " + matchRule
218                     + " will not match any identity.");
219         }
220     }
221 
NetworkTemplate(Parcel in)222     private NetworkTemplate(Parcel in) {
223         mMatchRule = in.readInt();
224         mSubscriberId = in.readString();
225         mMatchSubscriberIds = in.createStringArray();
226         mNetworkId = in.readString();
227         mMetered = in.readInt();
228         mRoaming = in.readInt();
229         mDefaultNetwork = in.readInt();
230     }
231 
232     @Override
writeToParcel(Parcel dest, int flags)233     public void writeToParcel(Parcel dest, int flags) {
234         dest.writeInt(mMatchRule);
235         dest.writeString(mSubscriberId);
236         dest.writeStringArray(mMatchSubscriberIds);
237         dest.writeString(mNetworkId);
238         dest.writeInt(mMetered);
239         dest.writeInt(mRoaming);
240         dest.writeInt(mDefaultNetwork);
241     }
242 
243     @Override
describeContents()244     public int describeContents() {
245         return 0;
246     }
247 
248     @Override
toString()249     public String toString() {
250         final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
251         builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
252         if (mSubscriberId != null) {
253             builder.append(", subscriberId=").append(
254                     NetworkIdentity.scrubSubscriberId(mSubscriberId));
255         }
256         if (mMatchSubscriberIds != null) {
257             builder.append(", matchSubscriberIds=").append(
258                     Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
259         }
260         if (mNetworkId != null) {
261             builder.append(", networkId=").append(mNetworkId);
262         }
263         if (mMetered != METERED_ALL) {
264             builder.append(", metered=").append(NetworkStats.meteredToString(mMetered));
265         }
266         if (mRoaming != ROAMING_ALL) {
267             builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming));
268         }
269         if (mDefaultNetwork != DEFAULT_NETWORK_ALL) {
270             builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
271                     mDefaultNetwork));
272         }
273         return builder.toString();
274     }
275 
276     @Override
hashCode()277     public int hashCode() {
278         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
279                 mDefaultNetwork);
280     }
281 
282     @Override
equals(Object obj)283     public boolean equals(Object obj) {
284         if (obj instanceof NetworkTemplate) {
285             final NetworkTemplate other = (NetworkTemplate) obj;
286             return mMatchRule == other.mMatchRule
287                     && Objects.equals(mSubscriberId, other.mSubscriberId)
288                     && Objects.equals(mNetworkId, other.mNetworkId)
289                     && mMetered == other.mMetered
290                     && mRoaming == other.mRoaming
291                     && mDefaultNetwork == other.mDefaultNetwork;
292         }
293         return false;
294     }
295 
isMatchRuleMobile()296     public boolean isMatchRuleMobile() {
297         switch (mMatchRule) {
298             case MATCH_MOBILE:
299             case MATCH_MOBILE_WILDCARD:
300                 return true;
301             default:
302                 return false;
303         }
304     }
305 
isPersistable()306     public boolean isPersistable() {
307         switch (mMatchRule) {
308             case MATCH_MOBILE_WILDCARD:
309             case MATCH_WIFI_WILDCARD:
310                 return false;
311             default:
312                 return true;
313         }
314     }
315 
316     @UnsupportedAppUsage
getMatchRule()317     public int getMatchRule() {
318         return mMatchRule;
319     }
320 
321     @UnsupportedAppUsage
getSubscriberId()322     public String getSubscriberId() {
323         return mSubscriberId;
324     }
325 
getNetworkId()326     public String getNetworkId() {
327         return mNetworkId;
328     }
329 
330     /**
331      * Test if given {@link NetworkIdentity} matches this template.
332      */
matches(NetworkIdentity ident)333     public boolean matches(NetworkIdentity ident) {
334         if (!matchesMetered(ident)) return false;
335         if (!matchesRoaming(ident)) return false;
336         if (!matchesDefaultNetwork(ident)) return false;
337 
338         switch (mMatchRule) {
339             case MATCH_MOBILE:
340                 return matchesMobile(ident);
341             case MATCH_WIFI:
342                 return matchesWifi(ident);
343             case MATCH_ETHERNET:
344                 return matchesEthernet(ident);
345             case MATCH_MOBILE_WILDCARD:
346                 return matchesMobileWildcard(ident);
347             case MATCH_WIFI_WILDCARD:
348                 return matchesWifiWildcard(ident);
349             case MATCH_BLUETOOTH:
350                 return matchesBluetooth(ident);
351             case MATCH_PROXY:
352                 return matchesProxy(ident);
353             default:
354                 // We have no idea what kind of network template we are, so we
355                 // just claim not to match anything.
356                 return false;
357         }
358     }
359 
matchesMetered(NetworkIdentity ident)360     private boolean matchesMetered(NetworkIdentity ident) {
361         return (mMetered == METERED_ALL)
362             || (mMetered == METERED_YES && ident.mMetered)
363             || (mMetered == METERED_NO && !ident.mMetered);
364     }
365 
matchesRoaming(NetworkIdentity ident)366     private boolean matchesRoaming(NetworkIdentity ident) {
367         return (mRoaming == ROAMING_ALL)
368             || (mRoaming == ROAMING_YES && ident.mRoaming)
369             || (mRoaming == ROAMING_NO && !ident.mRoaming);
370     }
371 
matchesDefaultNetwork(NetworkIdentity ident)372     private boolean matchesDefaultNetwork(NetworkIdentity ident) {
373         return (mDefaultNetwork == DEFAULT_NETWORK_ALL)
374             || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork)
375             || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
376     }
377 
matchesSubscriberId(String subscriberId)378     public boolean matchesSubscriberId(String subscriberId) {
379         return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
380     }
381 
382     /**
383      * Check if mobile network with matching IMSI.
384      */
matchesMobile(NetworkIdentity ident)385     private boolean matchesMobile(NetworkIdentity ident) {
386         if (ident.mType == TYPE_WIMAX) {
387             // TODO: consider matching against WiMAX subscriber identity
388             return true;
389         } else {
390             return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
391                     && !ArrayUtils.isEmpty(mMatchSubscriberIds)
392                     && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
393         }
394     }
395 
396     /**
397      * Check if matches Wi-Fi network template.
398      */
matchesWifi(NetworkIdentity ident)399     private boolean matchesWifi(NetworkIdentity ident) {
400         switch (ident.mType) {
401             case TYPE_WIFI:
402                 return Objects.equals(
403                         removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
404             default:
405                 return false;
406         }
407     }
408 
409     /**
410      * Check if matches Ethernet network template.
411      */
matchesEthernet(NetworkIdentity ident)412     private boolean matchesEthernet(NetworkIdentity ident) {
413         if (ident.mType == TYPE_ETHERNET) {
414             return true;
415         }
416         return false;
417     }
418 
matchesMobileWildcard(NetworkIdentity ident)419     private boolean matchesMobileWildcard(NetworkIdentity ident) {
420         if (ident.mType == TYPE_WIMAX) {
421             return true;
422         } else {
423             return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered);
424         }
425     }
426 
matchesWifiWildcard(NetworkIdentity ident)427     private boolean matchesWifiWildcard(NetworkIdentity ident) {
428         switch (ident.mType) {
429             case TYPE_WIFI:
430             case TYPE_WIFI_P2P:
431                 return true;
432             default:
433                 return false;
434         }
435     }
436 
437     /**
438      * Check if matches Bluetooth network template.
439      */
matchesBluetooth(NetworkIdentity ident)440     private boolean matchesBluetooth(NetworkIdentity ident) {
441         if (ident.mType == TYPE_BLUETOOTH) {
442             return true;
443         }
444         return false;
445     }
446 
447     /**
448      * Check if matches Proxy network template.
449      */
matchesProxy(NetworkIdentity ident)450     private boolean matchesProxy(NetworkIdentity ident) {
451         return ident.mType == TYPE_PROXY;
452     }
453 
getMatchRuleName(int matchRule)454     private static String getMatchRuleName(int matchRule) {
455         switch (matchRule) {
456             case MATCH_MOBILE:
457                 return "MOBILE";
458             case MATCH_WIFI:
459                 return "WIFI";
460             case MATCH_ETHERNET:
461                 return "ETHERNET";
462             case MATCH_MOBILE_WILDCARD:
463                 return "MOBILE_WILDCARD";
464             case MATCH_WIFI_WILDCARD:
465                 return "WIFI_WILDCARD";
466             case MATCH_BLUETOOTH:
467                 return "BLUETOOTH";
468             case MATCH_PROXY:
469                 return "PROXY";
470             default:
471                 return "UNKNOWN(" + matchRule + ")";
472         }
473     }
474 
475     /**
476      * Examine the given template and normalize if it refers to a "merged"
477      * mobile subscriber. We pick the "lowest" merged subscriber as the primary
478      * for key purposes, and expand the template to match all other merged
479      * subscribers.
480      * <p>
481      * For example, given an incoming template matching B, and the currently
482      * active merge set [A,B], we'd return a new template that primarily matches
483      * A, but also matches B.
484      */
485     @UnsupportedAppUsage
normalize(NetworkTemplate template, String[] merged)486     public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
487         if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
488             // Requested template subscriber is part of the merge group; return
489             // a template that matches all merged subscribers.
490             return new NetworkTemplate(template.mMatchRule, merged[0], merged,
491                     template.mNetworkId);
492         } else {
493             return template;
494         }
495     }
496 
497     @UnsupportedAppUsage
498     public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
499         @Override
500         public NetworkTemplate createFromParcel(Parcel in) {
501             return new NetworkTemplate(in);
502         }
503 
504         @Override
505         public NetworkTemplate[] newArray(int size) {
506             return new NetworkTemplate[size];
507         }
508     };
509 
getBytesForBackup()510     public byte[] getBytesForBackup() throws IOException {
511         ByteArrayOutputStream baos = new ByteArrayOutputStream();
512         DataOutputStream out = new DataOutputStream(baos);
513 
514         out.writeInt(BACKUP_VERSION);
515 
516         out.writeInt(mMatchRule);
517         BackupUtils.writeString(out, mSubscriberId);
518         BackupUtils.writeString(out, mNetworkId);
519 
520         return baos.toByteArray();
521     }
522 
getNetworkTemplateFromBackup(DataInputStream in)523     public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
524             throws IOException, BackupUtils.BadVersionException {
525         int version = in.readInt();
526         if (version < 1 || version > BACKUP_VERSION) {
527             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
528         }
529 
530         int matchRule = in.readInt();
531         String subscriberId = BackupUtils.readString(in);
532         String networkId = BackupUtils.readString(in);
533 
534         if (!isKnownMatchRule(matchRule)) {
535             throw new BackupUtils.BadVersionException(
536                     "Restored network template contains unknown match rule " + matchRule);
537         }
538 
539         return new NetworkTemplate(matchRule, subscriberId, networkId);
540     }
541 }
542