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