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_ETHERNET; 20 import static android.net.ConnectivityManager.TYPE_WIFI; 21 import static android.net.ConnectivityManager.TYPE_WIFI_P2P; 22 import static android.net.ConnectivityManager.TYPE_WIMAX; 23 import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; 24 import static android.net.NetworkIdentity.scrubSubscriberId; 25 import static android.net.wifi.WifiInfo.removeDoubleQuotes; 26 import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; 27 import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; 28 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; 29 import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; 30 import static android.telephony.TelephonyManager.getNetworkClass; 31 import static com.android.internal.util.ArrayUtils.contains; 32 33 import android.content.res.Resources; 34 import android.os.Parcel; 35 import android.os.Parcelable; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.internal.util.Objects; 39 40 /** 41 * Template definition used to generically match {@link NetworkIdentity}, 42 * usually when collecting statistics. 43 * 44 * @hide 45 */ 46 public class NetworkTemplate implements Parcelable { 47 48 public static final int MATCH_MOBILE_ALL = 1; 49 public static final int MATCH_MOBILE_3G_LOWER = 2; 50 public static final int MATCH_MOBILE_4G = 3; 51 public static final int MATCH_WIFI = 4; 52 public static final int MATCH_ETHERNET = 5; 53 public static final int MATCH_MOBILE_WILDCARD = 6; 54 public static final int MATCH_WIFI_WILDCARD = 7; 55 56 /** 57 * Set of {@link NetworkInfo#getType()} that reflect data usage. 58 */ 59 private static final int[] DATA_USAGE_NETWORK_TYPES; 60 61 static { 62 DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray( 63 com.android.internal.R.array.config_data_usage_network_types); 64 } 65 66 private static boolean sForceAllNetworkTypes = false; 67 68 @VisibleForTesting 69 public static void forceAllNetworkTypes() { 70 sForceAllNetworkTypes = true; 71 } 72 73 /** 74 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 75 * the given IMSI. 76 */ 77 public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { 78 return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null); 79 } 80 81 /** 82 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 83 * the given IMSI that roughly meet a "3G" definition, or lower. 84 */ 85 @Deprecated 86 public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { 87 return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null); 88 } 89 90 /** 91 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 92 * the given IMSI that roughly meet a "4G" definition. 93 */ 94 @Deprecated 95 public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { 96 return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null); 97 } 98 99 /** 100 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, 101 * regardless of IMSI. 102 */ 103 public static NetworkTemplate buildTemplateMobileWildcard() { 104 return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); 105 } 106 107 /** 108 * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, 109 * regardless of SSID. 110 */ 111 public static NetworkTemplate buildTemplateWifiWildcard() { 112 return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); 113 } 114 115 @Deprecated 116 public static NetworkTemplate buildTemplateWifi() { 117 return buildTemplateWifiWildcard(); 118 } 119 120 /** 121 * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the 122 * given SSID. 123 */ 124 public static NetworkTemplate buildTemplateWifi(String networkId) { 125 return new NetworkTemplate(MATCH_WIFI, null, networkId); 126 } 127 128 /** 129 * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style 130 * networks together. 131 */ 132 public static NetworkTemplate buildTemplateEthernet() { 133 return new NetworkTemplate(MATCH_ETHERNET, null, null); 134 } 135 136 private final int mMatchRule; 137 private final String mSubscriberId; 138 private final String mNetworkId; 139 140 public NetworkTemplate(int matchRule, String subscriberId, String networkId) { 141 mMatchRule = matchRule; 142 mSubscriberId = subscriberId; 143 mNetworkId = networkId; 144 } 145 146 private NetworkTemplate(Parcel in) { 147 mMatchRule = in.readInt(); 148 mSubscriberId = in.readString(); 149 mNetworkId = in.readString(); 150 } 151 152 @Override 153 public void writeToParcel(Parcel dest, int flags) { 154 dest.writeInt(mMatchRule); 155 dest.writeString(mSubscriberId); 156 dest.writeString(mNetworkId); 157 } 158 159 @Override 160 public int describeContents() { 161 return 0; 162 } 163 164 @Override 165 public String toString() { 166 final StringBuilder builder = new StringBuilder("NetworkTemplate: "); 167 builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); 168 if (mSubscriberId != null) { 169 builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); 170 } 171 if (mNetworkId != null) { 172 builder.append(", networkId=").append(mNetworkId); 173 } 174 return builder.toString(); 175 } 176 177 @Override 178 public int hashCode() { 179 return Objects.hashCode(mMatchRule, mSubscriberId, mNetworkId); 180 } 181 182 @Override 183 public boolean equals(Object obj) { 184 if (obj instanceof NetworkTemplate) { 185 final NetworkTemplate other = (NetworkTemplate) obj; 186 return mMatchRule == other.mMatchRule 187 && Objects.equal(mSubscriberId, other.mSubscriberId) 188 && Objects.equal(mNetworkId, other.mNetworkId); 189 } 190 return false; 191 } 192 193 public int getMatchRule() { 194 return mMatchRule; 195 } 196 197 public String getSubscriberId() { 198 return mSubscriberId; 199 } 200 201 public String getNetworkId() { 202 return mNetworkId; 203 } 204 205 /** 206 * Test if given {@link NetworkIdentity} matches this template. 207 */ 208 public boolean matches(NetworkIdentity ident) { 209 switch (mMatchRule) { 210 case MATCH_MOBILE_ALL: 211 return matchesMobile(ident); 212 case MATCH_MOBILE_3G_LOWER: 213 return matchesMobile3gLower(ident); 214 case MATCH_MOBILE_4G: 215 return matchesMobile4g(ident); 216 case MATCH_WIFI: 217 return matchesWifi(ident); 218 case MATCH_ETHERNET: 219 return matchesEthernet(ident); 220 case MATCH_MOBILE_WILDCARD: 221 return matchesMobileWildcard(ident); 222 case MATCH_WIFI_WILDCARD: 223 return matchesWifiWildcard(ident); 224 default: 225 throw new IllegalArgumentException("unknown network template"); 226 } 227 } 228 229 /** 230 * Check if mobile network with matching IMSI. 231 */ 232 private boolean matchesMobile(NetworkIdentity ident) { 233 if (ident.mType == TYPE_WIMAX) { 234 // TODO: consider matching against WiMAX subscriber identity 235 return true; 236 } else { 237 return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) 238 && Objects.equal(mSubscriberId, ident.mSubscriberId)); 239 } 240 } 241 242 /** 243 * Check if mobile network classified 3G or lower with matching IMSI. 244 */ 245 private boolean matchesMobile3gLower(NetworkIdentity ident) { 246 ensureSubtypeAvailable(); 247 if (ident.mType == TYPE_WIMAX) { 248 return false; 249 } else if (matchesMobile(ident)) { 250 switch (getNetworkClass(ident.mSubType)) { 251 case NETWORK_CLASS_UNKNOWN: 252 case NETWORK_CLASS_2_G: 253 case NETWORK_CLASS_3_G: 254 return true; 255 } 256 } 257 return false; 258 } 259 260 /** 261 * Check if mobile network classified 4G with matching IMSI. 262 */ 263 private boolean matchesMobile4g(NetworkIdentity ident) { 264 ensureSubtypeAvailable(); 265 if (ident.mType == TYPE_WIMAX) { 266 // TODO: consider matching against WiMAX subscriber identity 267 return true; 268 } else if (matchesMobile(ident)) { 269 switch (getNetworkClass(ident.mSubType)) { 270 case NETWORK_CLASS_4_G: 271 return true; 272 } 273 } 274 return false; 275 } 276 277 /** 278 * Check if matches Wi-Fi network template. 279 */ 280 private boolean matchesWifi(NetworkIdentity ident) { 281 switch (ident.mType) { 282 case TYPE_WIFI: 283 return Objects.equal( 284 removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); 285 default: 286 return false; 287 } 288 } 289 290 /** 291 * Check if matches Ethernet network template. 292 */ 293 private boolean matchesEthernet(NetworkIdentity ident) { 294 if (ident.mType == TYPE_ETHERNET) { 295 return true; 296 } 297 return false; 298 } 299 300 private boolean matchesMobileWildcard(NetworkIdentity ident) { 301 if (ident.mType == TYPE_WIMAX) { 302 return true; 303 } else { 304 return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType); 305 } 306 } 307 308 private boolean matchesWifiWildcard(NetworkIdentity ident) { 309 switch (ident.mType) { 310 case TYPE_WIFI: 311 case TYPE_WIFI_P2P: 312 return true; 313 default: 314 return false; 315 } 316 } 317 318 private static String getMatchRuleName(int matchRule) { 319 switch (matchRule) { 320 case MATCH_MOBILE_3G_LOWER: 321 return "MOBILE_3G_LOWER"; 322 case MATCH_MOBILE_4G: 323 return "MOBILE_4G"; 324 case MATCH_MOBILE_ALL: 325 return "MOBILE_ALL"; 326 case MATCH_WIFI: 327 return "WIFI"; 328 case MATCH_ETHERNET: 329 return "ETHERNET"; 330 case MATCH_MOBILE_WILDCARD: 331 return "MOBILE_WILDCARD"; 332 case MATCH_WIFI_WILDCARD: 333 return "WIFI_WILDCARD"; 334 default: 335 return "UNKNOWN"; 336 } 337 } 338 339 private static void ensureSubtypeAvailable() { 340 if (COMBINE_SUBTYPE_ENABLED) { 341 throw new IllegalArgumentException( 342 "Unable to enforce 3G_LOWER template on combined data."); 343 } 344 } 345 346 public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { 347 @Override 348 public NetworkTemplate createFromParcel(Parcel in) { 349 return new NetworkTemplate(in); 350 } 351 352 @Override 353 public NetworkTemplate[] newArray(int size) { 354 return new NetworkTemplate[size]; 355 } 356 }; 357 } 358