[go: nahoru, domu]

1/*
2 * Copyright (C) 2006 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
17package com.android.internal.telephony.dataconnection;
18
19import android.content.Context;
20import android.os.PersistableBundle;
21import android.telephony.CarrierConfigManager;
22import android.telephony.Rlog;
23import android.telephony.ServiceState;
24import android.text.TextUtils;
25
26import com.android.internal.telephony.PhoneConstants;
27import com.android.internal.telephony.RILConstants;
28import com.android.internal.telephony.uicc.IccRecords;
29
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.List;
35import java.util.Locale;
36
37/**
38 * This class represents a apn setting for create PDP link
39 */
40public class ApnSetting {
41
42    static final String LOG_TAG = "ApnSetting";
43
44    private static final boolean DBG = false;
45
46    static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
47    static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";
48
49    public final String carrier;
50    public final String apn;
51    public final String proxy;
52    public final String port;
53    public final String mmsc;
54    public final String mmsProxy;
55    public final String mmsPort;
56    public final String user;
57    public final String password;
58    public final int authType;
59    public final String[] types;
60    public final int id;
61    public final String numeric;
62    public final String protocol;
63    public final String roamingProtocol;
64    public final int mtu;
65
66    /**
67      * Current status of APN
68      * true : enabled APN, false : disabled APN.
69      */
70    public final boolean carrierEnabled;
71    /**
72     * Radio Access Technology info
73     * To check what values can hold, refer to ServiceState.java.
74     * This should be spread to other technologies,
75     * but currently only used for LTE(14) and EHRPD(13).
76     */
77    private final int bearer;
78    /**
79      * Radio Access Technology info
80      * To check what values can hold, refer to ServiceState.java. This is a bitmask of radio
81      * technologies in ServiceState.
82      * This should be spread to other technologies,
83      * but currently only used for LTE(14) and EHRPD(13).
84      */
85    public final int bearerBitmask;
86
87    /* ID of the profile in the modem */
88    public final int profileId;
89    public final boolean modemCognitive;
90    public final int maxConns;
91    public final int waitTime;
92    public final int maxConnsTime;
93
94    /**
95      * MVNO match type. Possible values:
96      *   "spn": Service provider name.
97      *   "imsi": IMSI.
98      *   "gid": Group identifier level 1.
99      */
100    public final String mvnoType;
101    /**
102      * MVNO data. Examples:
103      *   "spn": A MOBILE, BEN NL
104      *   "imsi": 302720x94, 2060188
105      *   "gid": 4E, 33
106      */
107    public final String mvnoMatchData;
108
109    /**
110     * Indicates this APN setting is permanently failed and cannot be
111     * retried by the retry manager anymore.
112     * */
113    public boolean permanentFailed = false;
114
115    /**
116     * Metered APN types which would be accounted for in data usage. This is a map of subId ->
117     * set of metered apn strings for the carrier.
118     */
119    private static HashMap<Integer, HashSet<String>> sMeteredApnTypes = new HashMap<>();
120
121    /**
122     * Metered Roaming APN types which would be accounted for in data usage. This is a map of
123     * subId -> set of metered roaming apn strings for the carrier.
124     */
125    private static HashMap<Integer, HashSet<String>> sMeteredRoamingApnTypes = new HashMap<>();
126
127    public ApnSetting(int id, String numeric, String carrier, String apn,
128            String proxy, String port,
129            String mmsc, String mmsProxy, String mmsPort,
130            String user, String password, int authType, String[] types,
131            String protocol, String roamingProtocol, boolean carrierEnabled, int bearer,
132            int bearerBitmask, int profileId, boolean modemCognitive, int maxConns, int waitTime,
133            int maxConnsTime, int mtu, String mvnoType, String mvnoMatchData) {
134        this.id = id;
135        this.numeric = numeric;
136        this.carrier = carrier;
137        this.apn = apn;
138        this.proxy = proxy;
139        this.port = port;
140        this.mmsc = mmsc;
141        this.mmsProxy = mmsProxy;
142        this.mmsPort = mmsPort;
143        this.user = user;
144        this.password = password;
145        this.authType = authType;
146        this.types = new String[types.length];
147        for (int i = 0; i < types.length; i++) {
148            this.types[i] = types[i].toLowerCase(Locale.ROOT);
149        }
150        this.protocol = protocol;
151        this.roamingProtocol = roamingProtocol;
152        this.carrierEnabled = carrierEnabled;
153        this.bearer = bearer;
154        this.bearerBitmask = (bearerBitmask | ServiceState.getBitmaskForTech(bearer));
155        this.profileId = profileId;
156        this.modemCognitive = modemCognitive;
157        this.maxConns = maxConns;
158        this.waitTime = waitTime;
159        this.maxConnsTime = maxConnsTime;
160        this.mtu = mtu;
161        this.mvnoType = mvnoType;
162        this.mvnoMatchData = mvnoMatchData;
163
164    }
165
166    public ApnSetting(ApnSetting apn) {
167        this(apn.id, apn.numeric, apn.carrier, apn.apn, apn.proxy, apn.port, apn.mmsc, apn.mmsProxy,
168                apn.mmsPort, apn.user, apn.password, apn.authType, apn.types, apn.protocol,
169                apn.roamingProtocol, apn.carrierEnabled, apn.bearer, apn.bearerBitmask,
170                apn.profileId, apn.modemCognitive, apn.maxConns, apn.waitTime, apn.maxConnsTime,
171                apn.mtu, apn.mvnoType, apn.mvnoMatchData);
172    }
173
174    /**
175     * Creates an ApnSetting object from a string.
176     *
177     * @param data the string to read.
178     *
179     * The string must be in one of two formats (newlines added for clarity,
180     * spaces are optional):
181     *
182     * v1 format:
183     *   <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
184     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
185     *   <type>[| <type>...],
186     *
187     * v2 format:
188     *   [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
189     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
190     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
191     *
192     * v3 format:
193     *   [ApnSettingV3] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
194     *   <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
195     *   <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
196     *   <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
197     *   <mvnoType>, <mvnoMatchData>
198     *
199     * Note that the strings generated by toString() do not contain the username
200     * and password and thus cannot be read by this method.
201     */
202    public static ApnSetting fromString(String data) {
203        if (data == null) return null;
204
205        int version;
206        // matches() operates on the whole string, so append .* to the regex.
207        if (data.matches(V3_FORMAT_REGEX + ".*")) {
208            version = 3;
209            data = data.replaceFirst(V3_FORMAT_REGEX, "");
210        } else if (data.matches(V2_FORMAT_REGEX + ".*")) {
211            version = 2;
212            data = data.replaceFirst(V2_FORMAT_REGEX, "");
213        } else {
214            version = 1;
215        }
216
217        String[] a = data.split("\\s*,\\s*");
218        if (a.length < 14) {
219            return null;
220        }
221
222        int authType;
223        try {
224            authType = Integer.parseInt(a[12]);
225        } catch (NumberFormatException e) {
226            authType = 0;
227        }
228
229        String[] typeArray;
230        String protocol, roamingProtocol;
231        boolean carrierEnabled;
232        int bearerBitmask = 0;
233        int profileId = 0;
234        boolean modemCognitive = false;
235        int maxConns = 0;
236        int waitTime = 0;
237        int maxConnsTime = 0;
238        int mtu = PhoneConstants.UNSET_MTU;
239        String mvnoType = "";
240        String mvnoMatchData = "";
241        if (version == 1) {
242            typeArray = new String[a.length - 13];
243            System.arraycopy(a, 13, typeArray, 0, a.length - 13);
244            protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
245            roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
246            carrierEnabled = true;
247        } else {
248            if (a.length < 18) {
249                return null;
250            }
251            typeArray = a[13].split("\\s*\\|\\s*");
252            protocol = a[14];
253            roamingProtocol = a[15];
254            carrierEnabled = Boolean.parseBoolean(a[16]);
255
256            bearerBitmask = ServiceState.getBitmaskFromString(a[17]);
257
258            if (a.length > 22) {
259                modemCognitive = Boolean.parseBoolean(a[19]);
260                try {
261                    profileId = Integer.parseInt(a[18]);
262                    maxConns = Integer.parseInt(a[20]);
263                    waitTime = Integer.parseInt(a[21]);
264                    maxConnsTime = Integer.parseInt(a[22]);
265                } catch (NumberFormatException e) {
266                }
267            }
268            if (a.length > 23) {
269                try {
270                    mtu = Integer.parseInt(a[23]);
271                } catch (NumberFormatException e) {
272                }
273            }
274            if (a.length > 25) {
275                mvnoType = a[24];
276                mvnoMatchData = a[25];
277            }
278        }
279
280        return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
281                a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol,carrierEnabled,0,
282                bearerBitmask, profileId, modemCognitive, maxConns, waitTime, maxConnsTime, mtu,
283                mvnoType, mvnoMatchData);
284    }
285
286    /**
287     * Creates an array of ApnSetting objects from a string.
288     *
289     * @param data the string to read.
290     *
291     * Builds on top of the same format used by fromString, but allows for multiple entries
292     * separated by "; ".
293     */
294    public static List<ApnSetting> arrayFromString(String data) {
295        List<ApnSetting> retVal = new ArrayList<ApnSetting>();
296        if (TextUtils.isEmpty(data)) {
297            return retVal;
298        }
299        String[] apnStrings = data.split("\\s*;\\s*");
300        for (String apnString : apnStrings) {
301            ApnSetting apn = fromString(apnString);
302            if (apn != null) {
303                retVal.add(apn);
304            }
305        }
306        return retVal;
307    }
308
309    @Override
310    public String toString() {
311        StringBuilder sb = new StringBuilder();
312        sb.append("[ApnSettingV3] ")
313        .append(carrier)
314        .append(", ").append(id)
315        .append(", ").append(numeric)
316        .append(", ").append(apn)
317        .append(", ").append(proxy)
318        .append(", ").append(mmsc)
319        .append(", ").append(mmsProxy)
320        .append(", ").append(mmsPort)
321        .append(", ").append(port)
322        .append(", ").append(authType).append(", ");
323        for (int i = 0; i < types.length; i++) {
324            sb.append(types[i]);
325            if (i < types.length - 1) {
326                sb.append(" | ");
327            }
328        }
329        sb.append(", ").append(protocol);
330        sb.append(", ").append(roamingProtocol);
331        sb.append(", ").append(carrierEnabled);
332        sb.append(", ").append(bearer);
333        sb.append(", ").append(bearerBitmask);
334        sb.append(", ").append(profileId);
335        sb.append(", ").append(modemCognitive);
336        sb.append(", ").append(maxConns);
337        sb.append(", ").append(waitTime);
338        sb.append(", ").append(maxConnsTime);
339        sb.append(", ").append(mtu);
340        sb.append(", ").append(mvnoType);
341        sb.append(", ").append(mvnoMatchData);
342        sb.append(", ").append(permanentFailed);
343        return sb.toString();
344    }
345
346    /**
347     * Returns true if there are MVNO params specified.
348     */
349    public boolean hasMvnoParams() {
350        return !TextUtils.isEmpty(mvnoType) && !TextUtils.isEmpty(mvnoMatchData);
351    }
352
353    public boolean canHandleType(String type) {
354        if (!carrierEnabled) return false;
355        for (String t : types) {
356            // DEFAULT handles all, and HIPRI is handled by DEFAULT
357            if (t.equalsIgnoreCase(type) ||
358                    t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) ||
359                    (t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) &&
360                    type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) {
361                return true;
362            }
363        }
364        return false;
365    }
366
367    private static boolean imsiMatches(String imsiDB, String imsiSIM) {
368        // Note: imsiDB value has digit number or 'x' character for seperating USIM information
369        // for MVNO operator. And then digit number is matched at same order and 'x' character
370        // could replace by any digit number.
371        // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator,
372        //     that means first 6 digits, 8th and 9th digit
373        //     should be set in USIM for GG Operator.
374        int len = imsiDB.length();
375        int idxCompare = 0;
376
377        if (len <= 0) return false;
378        if (len > imsiSIM.length()) return false;
379
380        for (int idx=0; idx<len; idx++) {
381            char c = imsiDB.charAt(idx);
382            if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) {
383                continue;
384            } else {
385                return false;
386            }
387        }
388        return true;
389    }
390
391    public static boolean mvnoMatches(IccRecords r, String mvnoType, String mvnoMatchData) {
392        if (mvnoType.equalsIgnoreCase("spn")) {
393            if ((r.getServiceProviderName() != null) &&
394                    r.getServiceProviderName().equalsIgnoreCase(mvnoMatchData)) {
395                return true;
396            }
397        } else if (mvnoType.equalsIgnoreCase("imsi")) {
398            String imsiSIM = r.getIMSI();
399            if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) {
400                return true;
401            }
402        } else if (mvnoType.equalsIgnoreCase("gid")) {
403            String gid1 = r.getGid1();
404            int mvno_match_data_length = mvnoMatchData.length();
405            if ((gid1 != null) && (gid1.length() >= mvno_match_data_length) &&
406                    gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) {
407                return true;
408            }
409        }
410        return false;
411    }
412
413    public static boolean isMeteredApnType(String type, Context context, int subId,
414                                           boolean isRoaming) {
415
416        HashMap<Integer, HashSet<String>> meteredApnTypesCache = (isRoaming) ?
417                sMeteredApnTypes : sMeteredRoamingApnTypes;
418        String carrierConfig = (isRoaming) ?
419                CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS :
420                CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS;
421
422        synchronized (meteredApnTypesCache) {
423            HashSet<String> meteredApnSet = meteredApnTypesCache.get(subId);
424
425            // In case of cache miss, we need to look up the settings from carrier config.
426            if (meteredApnSet == null) {
427                // Retrieve the metered APN types from carrier config
428                CarrierConfigManager configManager = (CarrierConfigManager)
429                        context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
430                if (configManager == null) {
431                    Rlog.e(LOG_TAG, "Carrier config service is not available");
432                    return true;
433                }
434
435                PersistableBundle b = configManager.getConfigForSubId(subId);
436                if (b == null) {
437                    Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId);
438                    return true;
439                }
440
441                String[] meteredApnTypes = b.getStringArray(carrierConfig);
442                if (meteredApnTypes == null) {
443                    Rlog.e(LOG_TAG, carrierConfig +  " is not available. " + "subId = " + subId);
444                    return true;
445                }
446
447                meteredApnSet = new HashSet<String>(Arrays.asList(meteredApnTypes));
448                meteredApnTypesCache.put(subId, meteredApnSet);
449                if (DBG) {
450                    Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " +
451                            Arrays.toString(meteredApnSet.toArray()) +
452                            " isRoaming: " + isRoaming);
453                }
454            }
455            // If all types of APN are metered, then this APN setting must be metered.
456            if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) {
457                if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming);
458                return true;
459            }
460
461            if (meteredApnSet.contains(type)) {
462                if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming);
463                return true;
464            } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) {
465                // Assuming no configuration error, if at least one APN type is
466                // metered, then this APN setting is metered.
467                if (meteredApnSet.size() > 0) {
468                    if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " +
469                            isRoaming);
470                    return true;
471                }
472            }
473        }
474        if (DBG) Rlog.d(LOG_TAG, type + " is not metered. isRoaming: " + isRoaming);
475        return false;
476    }
477
478    public boolean isMetered(Context context, int subId, boolean isRoaming ) {
479        for (String type : types) {
480            // If one of the APN type is metered, then this APN setting is metered.
481            if (isMeteredApnType(type, context, subId, isRoaming)) {
482                if (DBG) Rlog.d(LOG_TAG, "Metered. APN = " + toString() +
483                        "isRoaming: " + isRoaming);
484                return true;
485            }
486        }
487        if (DBG) Rlog.d(LOG_TAG, "Not metered. APN = " + toString() + "isRoaming: " + isRoaming);
488        return false;
489    }
490
491    // TODO - if we have this function we should also have hashCode.
492    // Also should handle changes in type order and perhaps case-insensitivity
493    @Override
494    public boolean equals(Object o) {
495        if (o instanceof ApnSetting == false) {
496            return false;
497        }
498
499        ApnSetting other = (ApnSetting) o;
500
501        return carrier.equals(other.carrier) &&
502                id == other.id &&
503                numeric.equals(other.numeric) &&
504                apn.equals(other.apn) &&
505                proxy.equals(other.proxy) &&
506                mmsc.equals(other.mmsc) &&
507                mmsProxy.equals(other.mmsProxy) &&
508                port.equals(other.port) &&
509                authType == other.authType &&
510                Arrays.deepEquals(types, other.types) &&
511                protocol.equals(other.protocol) &&
512                roamingProtocol.equals(other.roamingProtocol) &&
513                carrierEnabled == other.carrierEnabled &&
514                bearer == other.bearer &&
515                bearerBitmask == other.bearerBitmask &&
516                profileId == other.profileId &&
517                modemCognitive == other.modemCognitive &&
518                maxConns == other.maxConns &&
519                waitTime == other.waitTime &&
520                maxConnsTime == other.maxConnsTime &&
521                mtu == other.mtu &&
522                mvnoType.equals(other.mvnoType) &&
523                mvnoMatchData.equals(other.mvnoMatchData);
524    }
525}
526