/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net;

import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeMobile;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.service.NetworkIdentityProto;
import android.telephony.TelephonyManager;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import java.util.Objects;

Network definition that includes strong identity. Analogous to combining NetworkInfo and an IMSI.
@hide
/** * Network definition that includes strong identity. Analogous to combining * {@link NetworkInfo} and an IMSI. * * @hide */
public class NetworkIdentity implements Comparable<NetworkIdentity> { private static final String TAG = "NetworkIdentity";
When enabled, combine all mSubType together under SUBTYPE_COMBINED.
Deprecated:we no longer offer to collect statistics on a per-subtype basis; this is always disabled.
/** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. * * @deprecated we no longer offer to collect statistics on a per-subtype * basis; this is always disabled. */
@Deprecated public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; final int mType; final int mSubType; final String mSubscriberId; final String mNetworkId; final boolean mRoaming; final boolean mMetered; final boolean mDefaultNetwork; public NetworkIdentity( int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork) { mType = type; mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; mMetered = metered; mDefaultNetwork = defaultNetwork; } @Override public int hashCode() { return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, mDefaultNetwork); } @Override public boolean equals(Object obj) { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming && Objects.equals(mSubscriberId, ident.mSubscriberId) && Objects.equals(mNetworkId, ident.mNetworkId) && mMetered == ident.mMetered && mDefaultNetwork == ident.mDefaultNetwork; } return false; } @Override public String toString() { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); if (COMBINE_SUBTYPE_ENABLED) { builder.append("COMBINED"); } else if (ConnectivityManager.isNetworkTypeMobile(mType)) { builder.append(TelephonyManager.getNetworkTypeName(mSubType)); } else { builder.append(mSubType); } if (mSubscriberId != null) { builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); } if (mRoaming) { builder.append(", ROAMING"); } builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); return builder.append("}").toString(); } public void writeToProto(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); proto.write(NetworkIdentityProto.TYPE, mType); // Not dumping mSubType, subtypes are no longer supported. if (mSubscriberId != null) { proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId)); } proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); proto.end(start); } public int getType() { return mType; } public int getSubType() { return mSubType; } public String getSubscriberId() { return mSubscriberId; } public String getNetworkId() { return mNetworkId; } public boolean getRoaming() { return mRoaming; } public boolean getMetered() { return mMetered; } public boolean getDefaultNetwork() { return mDefaultNetwork; }
Scrub given IMSI on production builds.
/** * Scrub given IMSI on production builds. */
public static String scrubSubscriberId(String subscriberId) { if (Build.IS_ENG) { return subscriberId; } else if (subscriberId != null) { // TODO: parse this as MCC+MNC instead of hard-coding return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "..."; } else { return "null"; } }
Scrub given IMSI on production builds.
/** * Scrub given IMSI on production builds. */
public static String[] scrubSubscriberId(String[] subscriberId) { if (subscriberId == null) return null; final String[] res = new String[subscriberId.length]; for (int i = 0; i < res.length; i++) { res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]); } return res; }
Build a NetworkIdentity from the given NetworkState, assuming that any mobile networks are using the current IMSI.
/** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. */
public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, boolean defaultNetwork) { final int type = state.networkInfo.getType(); final int subType = state.networkInfo.getSubtype(); String subscriberId = null; String networkId = null; boolean roaming = !state.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); boolean metered = !state.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED && state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) { Slog.w(TAG, "Active mobile network without subscriber! ni = " + state.networkInfo); } } subscriberId = state.subscriberId; } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; } else { final WifiManager wifi = (WifiManager) context.getSystemService( Context.WIFI_SERVICE); final WifiInfo info = wifi.getConnectionInfo(); networkId = info != null ? info.getSSID() : null; } } return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, defaultNetwork); } @Override public int compareTo(NetworkIdentity another) { int res = Integer.compare(mType, another.mType); if (res == 0) { res = Integer.compare(mSubType, another.mSubType); } if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) { res = mSubscriberId.compareTo(another.mSubscriberId); } if (res == 0 && mNetworkId != null && another.mNetworkId != null) { res = mNetworkId.compareTo(another.mNetworkId); } if (res == 0) { res = Boolean.compare(mRoaming, another.mRoaming); } if (res == 0) { res = Boolean.compare(mMetered, another.mMetered); } if (res == 0) { res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork); } return res; } }