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