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