Home | History | Annotate | Download | only in net
      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_WIFI;
     22 import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
     23 import static android.net.ConnectivityManager.TYPE_WIMAX;
     24 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
     25 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
     26 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
     27 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
     28 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
     29 import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
     30 import static android.telephony.TelephonyManager.getNetworkClass;
     31 import static com.android.internal.util.ArrayUtils.contains;
     32 
     33 import android.content.res.Resources;
     34 import android.os.Parcel;
     35 import android.os.Parcelable;
     36 
     37 import com.android.internal.annotations.VisibleForTesting;
     38 import com.android.internal.util.ArrayUtils;
     39 
     40 import java.util.Arrays;
     41 import java.util.Objects;
     42 
     43 /**
     44  * Template definition used to generically match {@link NetworkIdentity},
     45  * usually when collecting statistics.
     46  *
     47  * @hide
     48  */
     49 public class NetworkTemplate implements Parcelable {
     50 
     51     public static final int MATCH_MOBILE_ALL = 1;
     52     @Deprecated
     53     public static final int MATCH_MOBILE_3G_LOWER = 2;
     54     @Deprecated
     55     public static final int MATCH_MOBILE_4G = 3;
     56     public static final int MATCH_WIFI = 4;
     57     public static final int MATCH_ETHERNET = 5;
     58     public static final int MATCH_MOBILE_WILDCARD = 6;
     59     public static final int MATCH_WIFI_WILDCARD = 7;
     60     public static final int MATCH_BLUETOOTH = 8;
     61 
     62     /**
     63      * Set of {@link NetworkInfo#getType()} that reflect data usage.
     64      */
     65     private static final int[] DATA_USAGE_NETWORK_TYPES;
     66 
     67     static {
     68         DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray(
     69                 com.android.internal.R.array.config_data_usage_network_types);
     70     }
     71 
     72     private static boolean sForceAllNetworkTypes = false;
     73 
     74     @VisibleForTesting
     75     public static void forceAllNetworkTypes() {
     76         sForceAllNetworkTypes = true;
     77     }
     78 
     79     /**
     80      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
     81      * the given IMSI.
     82      */
     83     public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
     84         return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
     85     }
     86 
     87     /**
     88      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
     89      * the given IMSI that roughly meet a "3G" definition, or lower.
     90      */
     91     @Deprecated
     92     public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
     93         return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
     94     }
     95 
     96     /**
     97      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
     98      * the given IMSI that roughly meet a "4G" definition.
     99      */
    100     @Deprecated
    101     public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
    102         return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
    103     }
    104 
    105     /**
    106      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
    107      * regardless of IMSI.
    108      */
    109     public static NetworkTemplate buildTemplateMobileWildcard() {
    110         return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
    111     }
    112 
    113     /**
    114      * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
    115      * regardless of SSID.
    116      */
    117     public static NetworkTemplate buildTemplateWifiWildcard() {
    118         return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
    119     }
    120 
    121     @Deprecated
    122     public static NetworkTemplate buildTemplateWifi() {
    123         return buildTemplateWifiWildcard();
    124     }
    125 
    126     /**
    127      * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
    128      * given SSID.
    129      */
    130     public static NetworkTemplate buildTemplateWifi(String networkId) {
    131         return new NetworkTemplate(MATCH_WIFI, null, networkId);
    132     }
    133 
    134     /**
    135      * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
    136      * networks together.
    137      */
    138     public static NetworkTemplate buildTemplateEthernet() {
    139         return new NetworkTemplate(MATCH_ETHERNET, null, null);
    140     }
    141 
    142     /**
    143      * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style
    144      * networks together.
    145      */
    146     public static NetworkTemplate buildTemplateBluetooth() {
    147         return new NetworkTemplate(MATCH_BLUETOOTH, null, null);
    148     }
    149 
    150     private final int mMatchRule;
    151     private final String mSubscriberId;
    152 
    153     /**
    154      * Ugh, templates are designed to target a single subscriber, but we might
    155      * need to match several "merged" subscribers. These are the subscribers
    156      * that should be considered to match this template.
    157      * <p>
    158      * Since the merge set is dynamic, it should <em>not</em> be persisted or
    159      * used for determining equality.
    160      */
    161     private final String[] mMatchSubscriberIds;
    162 
    163     private final String mNetworkId;
    164 
    165     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
    166         this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
    167     }
    168 
    169     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
    170             String networkId) {
    171         mMatchRule = matchRule;
    172         mSubscriberId = subscriberId;
    173         mMatchSubscriberIds = matchSubscriberIds;
    174         mNetworkId = networkId;
    175     }
    176 
    177     private NetworkTemplate(Parcel in) {
    178         mMatchRule = in.readInt();
    179         mSubscriberId = in.readString();
    180         mMatchSubscriberIds = in.createStringArray();
    181         mNetworkId = in.readString();
    182     }
    183 
    184     @Override
    185     public void writeToParcel(Parcel dest, int flags) {
    186         dest.writeInt(mMatchRule);
    187         dest.writeString(mSubscriberId);
    188         dest.writeStringArray(mMatchSubscriberIds);
    189         dest.writeString(mNetworkId);
    190     }
    191 
    192     @Override
    193     public int describeContents() {
    194         return 0;
    195     }
    196 
    197     @Override
    198     public String toString() {
    199         final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
    200         builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
    201         if (mSubscriberId != null) {
    202             builder.append(", subscriberId=").append(
    203                     NetworkIdentity.scrubSubscriberId(mSubscriberId));
    204         }
    205         if (mMatchSubscriberIds != null) {
    206             builder.append(", matchSubscriberIds=").append(
    207                     Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
    208         }
    209         if (mNetworkId != null) {
    210             builder.append(", networkId=").append(mNetworkId);
    211         }
    212         return builder.toString();
    213     }
    214 
    215     @Override
    216     public int hashCode() {
    217         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId);
    218     }
    219 
    220     @Override
    221     public boolean equals(Object obj) {
    222         if (obj instanceof NetworkTemplate) {
    223             final NetworkTemplate other = (NetworkTemplate) obj;
    224             return mMatchRule == other.mMatchRule
    225                     && Objects.equals(mSubscriberId, other.mSubscriberId)
    226                     && Objects.equals(mNetworkId, other.mNetworkId);
    227         }
    228         return false;
    229     }
    230 
    231     public boolean isMatchRuleMobile() {
    232         switch (mMatchRule) {
    233             case MATCH_MOBILE_3G_LOWER:
    234             case MATCH_MOBILE_4G:
    235             case MATCH_MOBILE_ALL:
    236             case MATCH_MOBILE_WILDCARD:
    237                 return true;
    238             default:
    239                 return false;
    240         }
    241     }
    242 
    243     public int getMatchRule() {
    244         return mMatchRule;
    245     }
    246 
    247     public String getSubscriberId() {
    248         return mSubscriberId;
    249     }
    250 
    251     public String getNetworkId() {
    252         return mNetworkId;
    253     }
    254 
    255     /**
    256      * Test if given {@link NetworkIdentity} matches this template.
    257      */
    258     public boolean matches(NetworkIdentity ident) {
    259         switch (mMatchRule) {
    260             case MATCH_MOBILE_ALL:
    261                 return matchesMobile(ident);
    262             case MATCH_MOBILE_3G_LOWER:
    263                 return matchesMobile3gLower(ident);
    264             case MATCH_MOBILE_4G:
    265                 return matchesMobile4g(ident);
    266             case MATCH_WIFI:
    267                 return matchesWifi(ident);
    268             case MATCH_ETHERNET:
    269                 return matchesEthernet(ident);
    270             case MATCH_MOBILE_WILDCARD:
    271                 return matchesMobileWildcard(ident);
    272             case MATCH_WIFI_WILDCARD:
    273                 return matchesWifiWildcard(ident);
    274             case MATCH_BLUETOOTH:
    275                 return matchesBluetooth(ident);
    276             default:
    277                 throw new IllegalArgumentException("unknown network template");
    278         }
    279     }
    280 
    281     /**
    282      * Check if mobile network with matching IMSI.
    283      */
    284     private boolean matchesMobile(NetworkIdentity ident) {
    285         if (ident.mType == TYPE_WIMAX) {
    286             // TODO: consider matching against WiMAX subscriber identity
    287             return true;
    288         } else {
    289             final boolean matchesType = (sForceAllNetworkTypes
    290                     || contains(DATA_USAGE_NETWORK_TYPES, ident.mType));
    291             return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
    292         }
    293     }
    294 
    295     /**
    296      * Check if mobile network classified 3G or lower with matching IMSI.
    297      */
    298     @Deprecated
    299     private boolean matchesMobile3gLower(NetworkIdentity ident) {
    300         ensureSubtypeAvailable();
    301         if (ident.mType == TYPE_WIMAX) {
    302             return false;
    303         } else if (matchesMobile(ident)) {
    304             switch (getNetworkClass(ident.mSubType)) {
    305                 case NETWORK_CLASS_UNKNOWN:
    306                 case NETWORK_CLASS_2_G:
    307                 case NETWORK_CLASS_3_G:
    308                     return true;
    309             }
    310         }
    311         return false;
    312     }
    313 
    314     /**
    315      * Check if mobile network classified 4G with matching IMSI.
    316      */
    317     @Deprecated
    318     private boolean matchesMobile4g(NetworkIdentity ident) {
    319         ensureSubtypeAvailable();
    320         if (ident.mType == TYPE_WIMAX) {
    321             // TODO: consider matching against WiMAX subscriber identity
    322             return true;
    323         } else if (matchesMobile(ident)) {
    324             switch (getNetworkClass(ident.mSubType)) {
    325                 case NETWORK_CLASS_4_G:
    326                     return true;
    327             }
    328         }
    329         return false;
    330     }
    331 
    332     /**
    333      * Check if matches Wi-Fi network template.
    334      */
    335     private boolean matchesWifi(NetworkIdentity ident) {
    336         switch (ident.mType) {
    337             case TYPE_WIFI:
    338                 return Objects.equals(
    339                         removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId));
    340             default:
    341                 return false;
    342         }
    343     }
    344 
    345     /**
    346      * Check if matches Ethernet network template.
    347      */
    348     private boolean matchesEthernet(NetworkIdentity ident) {
    349         if (ident.mType == TYPE_ETHERNET) {
    350             return true;
    351         }
    352         return false;
    353     }
    354 
    355     private boolean matchesMobileWildcard(NetworkIdentity ident) {
    356         if (ident.mType == TYPE_WIMAX) {
    357             return true;
    358         } else {
    359             return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
    360         }
    361     }
    362 
    363     private boolean matchesWifiWildcard(NetworkIdentity ident) {
    364         switch (ident.mType) {
    365             case TYPE_WIFI:
    366             case TYPE_WIFI_P2P:
    367                 return true;
    368             default:
    369                 return false;
    370         }
    371     }
    372 
    373     /**
    374      * Check if matches Bluetooth network template.
    375      */
    376     private boolean matchesBluetooth(NetworkIdentity ident) {
    377         if (ident.mType == TYPE_BLUETOOTH) {
    378             return true;
    379         }
    380         return false;
    381     }
    382 
    383     private static String getMatchRuleName(int matchRule) {
    384         switch (matchRule) {
    385             case MATCH_MOBILE_3G_LOWER:
    386                 return "MOBILE_3G_LOWER";
    387             case MATCH_MOBILE_4G:
    388                 return "MOBILE_4G";
    389             case MATCH_MOBILE_ALL:
    390                 return "MOBILE_ALL";
    391             case MATCH_WIFI:
    392                 return "WIFI";
    393             case MATCH_ETHERNET:
    394                 return "ETHERNET";
    395             case MATCH_MOBILE_WILDCARD:
    396                 return "MOBILE_WILDCARD";
    397             case MATCH_WIFI_WILDCARD:
    398                 return "WIFI_WILDCARD";
    399             case MATCH_BLUETOOTH:
    400                 return "BLUETOOTH";
    401             default:
    402                 return "UNKNOWN";
    403         }
    404     }
    405 
    406     private static void ensureSubtypeAvailable() {
    407         if (COMBINE_SUBTYPE_ENABLED) {
    408             throw new IllegalArgumentException(
    409                     "Unable to enforce 3G_LOWER template on combined data.");
    410         }
    411     }
    412 
    413     /**
    414      * Examine the given template and normalize if it refers to a "merged"
    415      * mobile subscriber. We pick the "lowest" merged subscriber as the primary
    416      * for key purposes, and expand the template to match all other merged
    417      * subscribers.
    418      * <p>
    419      * For example, given an incoming template matching B, and the currently
    420      * active merge set [A,B], we'd return a new template that primarily matches
    421      * A, but also matches B.
    422      */
    423     public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
    424         if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
    425             // Requested template subscriber is part of the merge group; return
    426             // a template that matches all merged subscribers.
    427             return new NetworkTemplate(template.mMatchRule, merged[0], merged,
    428                     template.mNetworkId);
    429         } else {
    430             return template;
    431         }
    432     }
    433 
    434     public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
    435         @Override
    436         public NetworkTemplate createFromParcel(Parcel in) {
    437             return new NetworkTemplate(in);
    438         }
    439 
    440         @Override
    441         public NetworkTemplate[] newArray(int size) {
    442             return new NetworkTemplate[size];
    443         }
    444     };
    445 }
    446