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