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 NetworkIdentity( int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork)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 hashCode()76 public int hashCode() { 77 return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, 78 mDefaultNetwork); 79 } 80 81 @Override equals(Object obj)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 toString()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 writeToProto(ProtoOutputStream proto, long tag)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 getType()138 public int getType() { 139 return mType; 140 } 141 getSubType()142 public int getSubType() { 143 return mSubType; 144 } 145 getSubscriberId()146 public String getSubscriberId() { 147 return mSubscriberId; 148 } 149 getNetworkId()150 public String getNetworkId() { 151 return mNetworkId; 152 } 153 getRoaming()154 public boolean getRoaming() { 155 return mRoaming; 156 } 157 getMetered()158 public boolean getMetered() { 159 return mMetered; 160 } 161 getDefaultNetwork()162 public boolean getDefaultNetwork() { 163 return mDefaultNetwork; 164 } 165 166 /** 167 * Scrub given IMSI on production builds. 168 */ scrubSubscriberId(String subscriberId)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 */ scrubSubscriberId(String[] subscriberId)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 */ buildNetworkIdentity(Context context, NetworkState state, boolean defaultNetwork)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 compareTo(NetworkIdentity another)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