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_WIFI;
     20 import static android.net.ConnectivityManager.getNetworkTypeName;
     21 import static android.net.ConnectivityManager.isNetworkTypeMobile;
     22 
     23 import android.content.Context;
     24 import android.net.wifi.WifiInfo;
     25 import android.net.wifi.WifiManager;
     26 import android.os.Build;
     27 import android.service.NetworkIdentityProto;
     28 import android.telephony.TelephonyManager;
     29 import android.util.Slog;
     30 import android.util.proto.ProtoOutputStream;
     31 
     32 import java.util.Objects;
     33 
     34 /**
     35  * Network definition that includes strong identity. Analogous to combining
     36  * {@link NetworkInfo} and an IMSI.
     37  *
     38  * @hide
     39  */
     40 public class NetworkIdentity implements Comparable<NetworkIdentity> {
     41     private static final String TAG = "NetworkIdentity";
     42 
     43     /**
     44      * When enabled, combine all {@link #mSubType} together under
     45      * {@link #SUBTYPE_COMBINED}.
     46      *
     47      * @deprecated we no longer offer to collect statistics on a per-subtype
     48      *             basis; this is always disabled.
     49      */
     50     @Deprecated
     51     public static final boolean COMBINE_SUBTYPE_ENABLED = true;
     52 
     53     public static final int SUBTYPE_COMBINED = -1;
     54 
     55     final int mType;
     56     final int mSubType;
     57     final String mSubscriberId;
     58     final String mNetworkId;
     59     final boolean mRoaming;
     60     final boolean mMetered;
     61     final boolean mDefaultNetwork;
     62 
     63     public NetworkIdentity(
     64             int type, int subType, String subscriberId, String networkId, boolean roaming,
     65             boolean metered, boolean defaultNetwork) {
     66         mType = type;
     67         mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
     68         mSubscriberId = subscriberId;
     69         mNetworkId = networkId;
     70         mRoaming = roaming;
     71         mMetered = metered;
     72         mDefaultNetwork = defaultNetwork;
     73     }
     74 
     75     @Override
     76     public int hashCode() {
     77         return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered,
     78                 mDefaultNetwork);
     79     }
     80 
     81     @Override
     82     public boolean equals(Object obj) {
     83         if (obj instanceof NetworkIdentity) {
     84             final NetworkIdentity ident = (NetworkIdentity) obj;
     85             return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
     86                     && Objects.equals(mSubscriberId, ident.mSubscriberId)
     87                     && Objects.equals(mNetworkId, ident.mNetworkId)
     88                     && mMetered == ident.mMetered
     89                     && mDefaultNetwork == ident.mDefaultNetwork;
     90         }
     91         return false;
     92     }
     93 
     94     @Override
     95     public String toString() {
     96         final StringBuilder builder = new StringBuilder("{");
     97         builder.append("type=").append(getNetworkTypeName(mType));
     98         builder.append(", subType=");
     99         if (COMBINE_SUBTYPE_ENABLED) {
    100             builder.append("COMBINED");
    101         } else if (ConnectivityManager.isNetworkTypeMobile(mType)) {
    102             builder.append(TelephonyManager.getNetworkTypeName(mSubType));
    103         } else {
    104             builder.append(mSubType);
    105         }
    106         if (mSubscriberId != null) {
    107             builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
    108         }
    109         if (mNetworkId != null) {
    110             builder.append(", networkId=").append(mNetworkId);
    111         }
    112         if (mRoaming) {
    113             builder.append(", ROAMING");
    114         }
    115         builder.append(", metered=").append(mMetered);
    116         builder.append(", defaultNetwork=").append(mDefaultNetwork);
    117         return builder.append("}").toString();
    118     }
    119 
    120     public void writeToProto(ProtoOutputStream proto, long tag) {
    121         final long start = proto.start(tag);
    122 
    123         proto.write(NetworkIdentityProto.TYPE, mType);
    124 
    125         // Not dumping mSubType, subtypes are no longer supported.
    126 
    127         if (mSubscriberId != null) {
    128             proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
    129         }
    130         proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
    131         proto.write(NetworkIdentityProto.ROAMING, mRoaming);
    132         proto.write(NetworkIdentityProto.METERED, mMetered);
    133         proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
    134 
    135         proto.end(start);
    136     }
    137 
    138     public int getType() {
    139         return mType;
    140     }
    141 
    142     public int getSubType() {
    143         return mSubType;
    144     }
    145 
    146     public String getSubscriberId() {
    147         return mSubscriberId;
    148     }
    149 
    150     public String getNetworkId() {
    151         return mNetworkId;
    152     }
    153 
    154     public boolean getRoaming() {
    155         return mRoaming;
    156     }
    157 
    158     public boolean getMetered() {
    159         return mMetered;
    160     }
    161 
    162     public boolean getDefaultNetwork() {
    163         return mDefaultNetwork;
    164     }
    165 
    166     /**
    167      * Scrub given IMSI on production builds.
    168      */
    169     public static String scrubSubscriberId(String subscriberId) {
    170         if (Build.IS_ENG) {
    171             return subscriberId;
    172         } else if (subscriberId != null) {
    173             // TODO: parse this as MCC+MNC instead of hard-coding
    174             return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "...";
    175         } else {
    176             return "null";
    177         }
    178     }
    179 
    180     /**
    181      * Scrub given IMSI on production builds.
    182      */
    183     public static String[] scrubSubscriberId(String[] subscriberId) {
    184         if (subscriberId == null) return null;
    185         final String[] res = new String[subscriberId.length];
    186         for (int i = 0; i < res.length; i++) {
    187             res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]);
    188         }
    189         return res;
    190     }
    191 
    192     /**
    193      * Build a {@link NetworkIdentity} from the given {@link NetworkState},
    194      * assuming that any mobile networks are using the current IMSI.
    195      */
    196     public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
    197             boolean defaultNetwork) {
    198         final int type = state.networkInfo.getType();
    199         final int subType = state.networkInfo.getSubtype();
    200 
    201         String subscriberId = null;
    202         String networkId = null;
    203         boolean roaming = !state.networkCapabilities.hasCapability(
    204                 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
    205         boolean metered = !state.networkCapabilities.hasCapability(
    206                 NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
    207 
    208         if (isNetworkTypeMobile(type)) {
    209             if (state.subscriberId == null) {
    210                 if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
    211                         state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
    212                     Slog.w(TAG, "Active mobile network without subscriber! ni = "
    213                             + state.networkInfo);
    214                 }
    215             }
    216 
    217             subscriberId = state.subscriberId;
    218 
    219         } else if (type == TYPE_WIFI) {
    220             if (state.networkId != null) {
    221                 networkId = state.networkId;
    222             } else {
    223                 final WifiManager wifi = (WifiManager) context.getSystemService(
    224                         Context.WIFI_SERVICE);
    225                 final WifiInfo info = wifi.getConnectionInfo();
    226                 networkId = info != null ? info.getSSID() : null;
    227             }
    228         }
    229 
    230         return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered,
    231                 defaultNetwork);
    232     }
    233 
    234     @Override
    235     public int compareTo(NetworkIdentity another) {
    236         int res = Integer.compare(mType, another.mType);
    237         if (res == 0) {
    238             res = Integer.compare(mSubType, another.mSubType);
    239         }
    240         if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) {
    241             res = mSubscriberId.compareTo(another.mSubscriberId);
    242         }
    243         if (res == 0 && mNetworkId != null && another.mNetworkId != null) {
    244             res = mNetworkId.compareTo(another.mNetworkId);
    245         }
    246         if (res == 0) {
    247             res = Boolean.compare(mRoaming, another.mRoaming);
    248         }
    249         if (res == 0) {
    250             res = Boolean.compare(mMetered, another.mMetered);
    251         }
    252         if (res == 0) {
    253             res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork);
    254         }
    255         return res;
    256     }
    257 }
    258