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.app.PendingIntent;
20import android.content.res.Resources;
21import android.net.ConnectivityManager;
22import android.net.NetworkCapabilities;
23import android.net.NetworkConfig;
24import android.net.NetworkRequest;
25import android.telephony.Rlog;
26import android.text.TextUtils;
27import android.util.LocalLog;
28import android.util.SparseIntArray;
29
30import com.android.internal.R;
31import com.android.internal.telephony.DctConstants;
32import com.android.internal.telephony.Phone;
33import com.android.internal.telephony.PhoneConstants;
34import com.android.internal.telephony.RetryManager;
35import com.android.internal.util.IndentingPrintWriter;
36
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.util.ArrayDeque;
40import java.util.ArrayList;
41import java.util.List;
42import java.util.concurrent.atomic.AtomicBoolean;
43import java.util.concurrent.atomic.AtomicInteger;
44
45/**
46 * Maintain the Apn context
47 */
48public class ApnContext {
49
50    public final String LOG_TAG;
51    private final static String SLOG_TAG = "ApnContext";
52
53    protected static final boolean DBG = false;
54
55    private final Phone mPhone;
56
57    private final String mApnType;
58
59    private DctConstants.State mState;
60
61    public final int priority;
62
63    private ApnSetting mApnSetting;
64
65    DcAsyncChannel mDcAc;
66
67    String mReason;
68
69    PendingIntent mReconnectAlarmIntent;
70
71    /**
72     * user/app requested connection on this APN
73     */
74    AtomicBoolean mDataEnabled;
75
76    private final Object mRefCountLock = new Object();
77    private int mRefCount = 0;
78
79    /**
80     * carrier requirements met
81     */
82    AtomicBoolean mDependencyMet;
83
84    private final DcTracker mDcTracker;
85
86    /**
87     * Remember this as a change in this value to a more permissive state
88     * should cause us to retry even permanent failures
89     */
90    private boolean mConcurrentVoiceAndDataAllowed;
91
92    /**
93     * used to track a single connection request so disconnects can get ignored if
94     * obsolete.
95     */
96    private final AtomicInteger mConnectionGeneration = new AtomicInteger(0);
97
98    /**
99     * Retry manager that handles the APN retry and delays.
100     */
101    private final RetryManager mRetryManager;
102
103    /**
104     * AonContext constructor
105     * @param phone phone object
106     * @param apnType APN type (e.g. default, supl, mms, etc...)
107     * @param logTag Tag for logging
108     * @param config Network configuration
109     * @param tracker Data call tracker
110     */
111    public ApnContext(Phone phone, String apnType, String logTag, NetworkConfig config,
112            DcTracker tracker) {
113        mPhone = phone;
114        mApnType = apnType;
115        mState = DctConstants.State.IDLE;
116        setReason(Phone.REASON_DATA_ENABLED);
117        mDataEnabled = new AtomicBoolean(false);
118        mDependencyMet = new AtomicBoolean(config.dependencyMet);
119        priority = config.priority;
120        LOG_TAG = logTag;
121        mDcTracker = tracker;
122        mRetryManager = new RetryManager(phone, apnType);
123    }
124
125    /**
126     * Get the APN type
127     * @return The APN type
128     */
129    public String getApnType() {
130        return mApnType;
131    }
132
133    /**
134     * Get the data call async channel.
135     * @return The data call async channel
136     */
137    public synchronized DcAsyncChannel getDcAc() {
138        return mDcAc;
139    }
140
141    /**
142     * Set the data call async channel.
143     * @param dcac The data call async channel
144     */
145    public synchronized void setDataConnectionAc(DcAsyncChannel dcac) {
146        if (DBG) {
147            log("setDataConnectionAc: old dcac=" + mDcAc + " new dcac=" + dcac
148                    + " this=" + this);
149        }
150        mDcAc = dcac;
151    }
152
153    /**
154     * Release data connection.
155     * @param reason The reason of releasing data connection
156     */
157    public synchronized void releaseDataConnection(String reason) {
158        if (mDcAc != null) {
159            mDcAc.tearDown(this, reason, null);
160            mDcAc = null;
161        }
162        setState(DctConstants.State.IDLE);
163    }
164
165    /**
166     * Get the reconnect intent.
167     * @return The reconnect intent
168     */
169    public synchronized PendingIntent getReconnectIntent() {
170        return mReconnectAlarmIntent;
171    }
172
173    /**
174     * Save the reconnect intent which can be used for cancelling later.
175     * @param intent The reconnect intent
176     */
177    public synchronized void setReconnectIntent(PendingIntent intent) {
178        mReconnectAlarmIntent = intent;
179    }
180
181    /**
182     * Get the current APN setting.
183     * @return APN setting
184     */
185    public synchronized ApnSetting getApnSetting() {
186        if (DBG) log("getApnSetting: apnSetting=" + mApnSetting);
187        return mApnSetting;
188    }
189
190    /**
191     * Set the APN setting.
192     * @param apnSetting APN setting
193     */
194    public synchronized void setApnSetting(ApnSetting apnSetting) {
195        if (DBG) log("setApnSetting: apnSetting=" + apnSetting);
196        mApnSetting = apnSetting;
197    }
198
199    /**
200     * Set the list of APN candidates which will be used for data call setup later.
201     * @param waitingApns List of APN candidates
202     */
203    public synchronized void setWaitingApns(ArrayList<ApnSetting> waitingApns) {
204        mRetryManager.setWaitingApns(waitingApns);
205    }
206
207    /**
208     * Get the next available APN to try.
209     * @return APN setting which will be used for data call setup. Return null if there is no
210     * APN can be retried.
211     */
212    public ApnSetting getNextApnSetting() {
213        return mRetryManager.getNextApnSetting();
214    }
215
216    /**
217     * Save the modem suggested delay for retrying the current APN.
218     * This method is called when we get the suggested delay from RIL.
219     * @param delay The delay in milliseconds
220     */
221    public void setModemSuggestedDelay(long delay) {
222        mRetryManager.setModemSuggestedDelay(delay);
223    }
224
225    /**
226     * Get the delay for trying the next APN setting if the current one failed.
227     * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter
228     *                        delay.
229     * @return The delay in milliseconds
230     */
231    public long getDelayForNextApn(boolean failFastEnabled) {
232        return mRetryManager.getDelayForNextApn(failFastEnabled || isFastRetryReason());
233    }
234
235    /**
236     * Mark the current APN setting permanently failed, which means it will not be retried anymore.
237     * @param apn APN setting
238     */
239    public void markApnPermanentFailed(ApnSetting apn) {
240        mRetryManager.markApnPermanentFailed(apn);
241    }
242
243    /**
244     * Get the list of waiting APNs.
245     * @return the list of waiting APNs
246     */
247    public ArrayList<ApnSetting> getWaitingApns() {
248        return mRetryManager.getWaitingApns();
249    }
250
251    /**
252     * Save the state indicating concurrent voice/data allowed.
253     * @param allowed True if concurrent voice/data is allowed
254     */
255    public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) {
256        mConcurrentVoiceAndDataAllowed = allowed;
257    }
258
259    /**
260     * Get the state indicating concurrent voice/data allowed.
261     * @return True if concurrent voice/data is allowed
262     */
263    public synchronized boolean isConcurrentVoiceAndDataAllowed() {
264        return mConcurrentVoiceAndDataAllowed;
265    }
266
267    /**
268     * Set the current data call state.
269     * @param s Current data call state
270     */
271    public synchronized void setState(DctConstants.State s) {
272        if (DBG) {
273            log("setState: " + s + ", previous state:" + mState);
274        }
275
276        mState = s;
277
278        if (mState == DctConstants.State.FAILED) {
279            if (mRetryManager.getWaitingApns() != null) {
280                mRetryManager.getWaitingApns().clear(); // when teardown the connection and set to IDLE
281            }
282        }
283    }
284
285    /**
286     * Get the current data call state.
287     * @return The current data call state
288     */
289    public synchronized DctConstants.State getState() {
290        return mState;
291    }
292
293    /**
294     * Check whether the data call is disconnected or not.
295     * @return True if the data call is disconnected
296     */
297    public boolean isDisconnected() {
298        DctConstants.State currentState = getState();
299        return ((currentState == DctConstants.State.IDLE) ||
300                    currentState == DctConstants.State.FAILED);
301    }
302
303    /**
304     * Set the reason for data call connection.
305     * @param reason Reason for data call connection
306     */
307    public synchronized void setReason(String reason) {
308        if (DBG) {
309            log("set reason as " + reason + ",current state " + mState);
310        }
311        mReason = reason;
312    }
313
314    /**
315     * Get the reason for data call connection.
316     * @return The reason for data call connection
317     */
318    public synchronized String getReason() {
319        return mReason;
320    }
321
322    /**
323     * Check if ready for data call connection
324     * @return True if ready, otherwise false.
325     */
326    public boolean isReady() {
327        return mDataEnabled.get() && mDependencyMet.get();
328    }
329
330    /**
331     * Check if the data call is in the state which allow connecting.
332     * @return True if allowed, otherwise false.
333     */
334    public boolean isConnectable() {
335        return isReady() && ((mState == DctConstants.State.IDLE)
336                                || (mState == DctConstants.State.SCANNING)
337                                || (mState == DctConstants.State.RETRYING)
338                                || (mState == DctConstants.State.FAILED));
339    }
340
341    /**
342     * Check if apn reason is fast retry reason which should apply shorter delay between apn re-try.
343     * @return True if it is fast retry reason, otherwise false.
344     */
345    private boolean isFastRetryReason() {
346        return Phone.REASON_NW_TYPE_CHANGED.equals(mReason) ||
347                Phone.REASON_APN_CHANGED.equals(mReason);
348    }
349
350    /** Check if the data call is in connected or connecting state.
351     * @return True if the data call is in connected or connecting state
352     */
353    public boolean isConnectedOrConnecting() {
354        return isReady() && ((mState == DctConstants.State.CONNECTED)
355                                || (mState == DctConstants.State.CONNECTING)
356                                || (mState == DctConstants.State.SCANNING)
357                                || (mState == DctConstants.State.RETRYING));
358    }
359
360    /**
361     * Set data call enabled/disabled state.
362     * @param enabled True if data call is enabled
363     */
364    public void setEnabled(boolean enabled) {
365        if (DBG) {
366            log("set enabled as " + enabled + ", current state is " + mDataEnabled.get());
367        }
368        mDataEnabled.set(enabled);
369    }
370
371    /**
372     * Check if the data call is enabled or not.
373     * @return True if enabled
374     */
375    public boolean isEnabled() {
376        return mDataEnabled.get();
377    }
378
379    public void setDependencyMet(boolean met) {
380        if (DBG) {
381            log("set mDependencyMet as " + met + " current state is " + mDependencyMet.get());
382        }
383        mDependencyMet.set(met);
384    }
385
386    public boolean getDependencyMet() {
387       return mDependencyMet.get();
388    }
389
390    public boolean isProvisioningApn() {
391        String provisioningApn = mPhone.getContext().getResources()
392                .getString(R.string.mobile_provisioning_apn);
393        if (!TextUtils.isEmpty(provisioningApn) &&
394                (mApnSetting != null) && (mApnSetting.apn != null)) {
395            return (mApnSetting.apn.equals(provisioningApn));
396        } else {
397            return false;
398        }
399    }
400
401    private final ArrayList<LocalLog> mLocalLogs = new ArrayList<>();
402    private final ArrayList<NetworkRequest> mNetworkRequests = new ArrayList<>();
403    private final ArrayDeque<LocalLog> mHistoryLogs = new ArrayDeque<>();
404    private final static int MAX_HISTORY_LOG_COUNT = 4;
405
406    public void requestLog(String str) {
407        synchronized (mRefCountLock) {
408            for (LocalLog l : mLocalLogs) {
409                l.log(str);
410            }
411        }
412    }
413
414    public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
415        synchronized (mRefCountLock) {
416            if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) {
417                log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size());
418            } else {
419                mLocalLogs.add(log);
420                mNetworkRequests.add(networkRequest);
421                mDcTracker.setEnabled(apnIdForApnName(mApnType), true);
422            }
423        }
424    }
425
426    public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) {
427        synchronized (mRefCountLock) {
428            if (mLocalLogs.contains(log) == false) {
429                log.log("ApnContext.releaseNetwork can't find this log");
430            } else {
431                mLocalLogs.remove(log);
432            }
433            if (mNetworkRequests.contains(networkRequest) == false) {
434                log.log("ApnContext.releaseNetwork can't find this request ("
435                        + networkRequest + ")");
436            } else {
437                mNetworkRequests.remove(networkRequest);
438                log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() +
439                        " requests.");
440                if (mNetworkRequests.size() == 0) {
441                    mDcTracker.setEnabled(apnIdForApnName(mApnType), false);
442                }
443            }
444        }
445    }
446
447    public List<NetworkRequest> getNetworkRequests() {
448        synchronized (mRefCountLock) {
449            return new ArrayList<NetworkRequest>(mNetworkRequests);
450        }
451    }
452
453    public boolean hasNoRestrictedRequests(boolean excludeDun) {
454        synchronized (mRefCountLock) {
455            for (NetworkRequest nr : mNetworkRequests) {
456                if (excludeDun &&
457                        nr.networkCapabilities.hasCapability(
458                        NetworkCapabilities.NET_CAPABILITY_DUN)) {
459                    continue;
460                }
461                if (nr.networkCapabilities.hasCapability(
462                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) {
463                    return false;
464                }
465            }
466        }
467        return true;
468    }
469
470    private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray();
471
472    public void resetErrorCodeRetries() {
473        requestLog("ApnContext.resetErrorCodeRetries");
474        if (DBG) log("ApnContext.resetErrorCodeRetries");
475
476        String[] config = mPhone.getContext().getResources().getStringArray(
477                com.android.internal.R.array.config_cell_retries_per_error_code);
478        synchronized (mRetriesLeftPerErrorCode) {
479            mRetriesLeftPerErrorCode.clear();
480
481            for (String c : config) {
482                String errorValue[] = c.split(",");
483                if (errorValue != null && errorValue.length == 2) {
484                    int count = 0;
485                    int errorCode = 0;
486                    try {
487                        errorCode = Integer.parseInt(errorValue[0]);
488                        count = Integer.parseInt(errorValue[1]);
489                    } catch (NumberFormatException e) {
490                        log("Exception parsing config_retries_per_error_code: " + e);
491                        continue;
492                    }
493                    if (count > 0 && errorCode > 0) {
494                        mRetriesLeftPerErrorCode.put(errorCode, count);
495                    }
496                } else {
497                    log("Exception parsing config_retries_per_error_code: " + c);
498                }
499            }
500        }
501    }
502
503    public boolean restartOnError(int errorCode) {
504        boolean result = false;
505        int retriesLeft = 0;
506        synchronized(mRetriesLeftPerErrorCode) {
507            retriesLeft = mRetriesLeftPerErrorCode.get(errorCode);
508            switch (retriesLeft) {
509                case 0: {
510                    // not set, never restart modem
511                    break;
512                }
513                case 1: {
514                    resetErrorCodeRetries();
515                    result = true;
516                    break;
517                }
518                default: {
519                    mRetriesLeftPerErrorCode.put(errorCode, retriesLeft - 1);
520                    result = false;
521                }
522            }
523        }
524        String str = "ApnContext.restartOnError(" + errorCode + ") found " + retriesLeft +
525                " and returned " + result;
526        if (DBG) log(str);
527        requestLog(str);
528        return result;
529    }
530
531    public int incAndGetConnectionGeneration() {
532        return mConnectionGeneration.incrementAndGet();
533    }
534
535    public int getConnectionGeneration() {
536        return mConnectionGeneration.get();
537    }
538
539    public long getInterApnDelay(boolean failFastEnabled) {
540        return mRetryManager.getInterApnDelay(failFastEnabled || isFastRetryReason());
541    }
542
543    public static int apnIdForType(int networkType) {
544        switch (networkType) {
545        case ConnectivityManager.TYPE_MOBILE:
546            return DctConstants.APN_DEFAULT_ID;
547        case ConnectivityManager.TYPE_MOBILE_MMS:
548            return DctConstants.APN_MMS_ID;
549        case ConnectivityManager.TYPE_MOBILE_SUPL:
550            return DctConstants.APN_SUPL_ID;
551        case ConnectivityManager.TYPE_MOBILE_DUN:
552            return DctConstants.APN_DUN_ID;
553        case ConnectivityManager.TYPE_MOBILE_FOTA:
554            return DctConstants.APN_FOTA_ID;
555        case ConnectivityManager.TYPE_MOBILE_IMS:
556            return DctConstants.APN_IMS_ID;
557        case ConnectivityManager.TYPE_MOBILE_CBS:
558            return DctConstants.APN_CBS_ID;
559        case ConnectivityManager.TYPE_MOBILE_IA:
560            return DctConstants.APN_IA_ID;
561        case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
562            return DctConstants.APN_EMERGENCY_ID;
563        default:
564            return DctConstants.APN_INVALID_ID;
565        }
566    }
567
568    public static int apnIdForNetworkRequest(NetworkRequest nr) {
569        NetworkCapabilities nc = nr.networkCapabilities;
570        // For now, ignore the bandwidth stuff
571        if (nc.getTransportTypes().length > 0 &&
572                nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false) {
573            return DctConstants.APN_INVALID_ID;
574        }
575
576        // in the near term just do 1-1 matches.
577        // TODO - actually try to match the set of capabilities
578        int apnId = DctConstants.APN_INVALID_ID;
579        boolean error = false;
580
581        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
582            apnId = DctConstants.APN_DEFAULT_ID;
583        }
584        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
585            if (apnId != DctConstants.APN_INVALID_ID) error = true;
586            apnId = DctConstants.APN_MMS_ID;
587        }
588        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
589            if (apnId != DctConstants.APN_INVALID_ID) error = true;
590            apnId = DctConstants.APN_SUPL_ID;
591        }
592        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
593            if (apnId != DctConstants.APN_INVALID_ID) error = true;
594            apnId = DctConstants.APN_DUN_ID;
595        }
596        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
597            if (apnId != DctConstants.APN_INVALID_ID) error = true;
598            apnId = DctConstants.APN_FOTA_ID;
599        }
600        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
601            if (apnId != DctConstants.APN_INVALID_ID) error = true;
602            apnId = DctConstants.APN_IMS_ID;
603        }
604        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
605            if (apnId != DctConstants.APN_INVALID_ID) error = true;
606            apnId = DctConstants.APN_CBS_ID;
607        }
608        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) {
609            if (apnId != DctConstants.APN_INVALID_ID) error = true;
610            apnId = DctConstants.APN_IA_ID;
611        }
612        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_RCS)) {
613            if (apnId != DctConstants.APN_INVALID_ID) error = true;
614
615            Rlog.d(SLOG_TAG, "RCS APN type not yet supported");
616        }
617        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
618            if (apnId != DctConstants.APN_INVALID_ID) error = true;
619
620            Rlog.d(SLOG_TAG, "XCAP APN type not yet supported");
621        }
622        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
623            if (apnId != DctConstants.APN_INVALID_ID) error = true;
624            apnId = DctConstants.APN_EMERGENCY_ID;
625        }
626        if (error) {
627            // TODO: If this error condition is removed, the framework's handling of
628            // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for
629            // say FOTA and INTERNET are marked as restricted.  This is not how
630            // NetworkCapabilities.maybeMarkCapabilitiesRestricted currently works.
631            Rlog.d(SLOG_TAG, "Multiple apn types specified in request - result is unspecified!");
632        }
633        if (apnId == DctConstants.APN_INVALID_ID) {
634            Rlog.d(SLOG_TAG, "Unsupported NetworkRequest in Telephony: nr=" + nr);
635        }
636        return apnId;
637    }
638
639    // TODO - kill The use of these strings
640    public static int apnIdForApnName(String type) {
641        switch (type) {
642            case PhoneConstants.APN_TYPE_DEFAULT:
643                return DctConstants.APN_DEFAULT_ID;
644            case PhoneConstants.APN_TYPE_MMS:
645                return DctConstants.APN_MMS_ID;
646            case PhoneConstants.APN_TYPE_SUPL:
647                return DctConstants.APN_SUPL_ID;
648            case PhoneConstants.APN_TYPE_DUN:
649                return DctConstants.APN_DUN_ID;
650            case PhoneConstants.APN_TYPE_HIPRI:
651                return DctConstants.APN_HIPRI_ID;
652            case PhoneConstants.APN_TYPE_IMS:
653                return DctConstants.APN_IMS_ID;
654            case PhoneConstants.APN_TYPE_FOTA:
655                return DctConstants.APN_FOTA_ID;
656            case PhoneConstants.APN_TYPE_CBS:
657                return DctConstants.APN_CBS_ID;
658            case PhoneConstants.APN_TYPE_IA:
659                return DctConstants.APN_IA_ID;
660            case PhoneConstants.APN_TYPE_EMERGENCY:
661                return DctConstants.APN_EMERGENCY_ID;
662            default:
663                return DctConstants.APN_INVALID_ID;
664        }
665    }
666
667    private static String apnNameForApnId(int id) {
668        switch (id) {
669            case DctConstants.APN_DEFAULT_ID:
670                return PhoneConstants.APN_TYPE_DEFAULT;
671            case DctConstants.APN_MMS_ID:
672                return PhoneConstants.APN_TYPE_MMS;
673            case DctConstants.APN_SUPL_ID:
674                return PhoneConstants.APN_TYPE_SUPL;
675            case DctConstants.APN_DUN_ID:
676                return PhoneConstants.APN_TYPE_DUN;
677            case DctConstants.APN_HIPRI_ID:
678                return PhoneConstants.APN_TYPE_HIPRI;
679            case DctConstants.APN_IMS_ID:
680                return PhoneConstants.APN_TYPE_IMS;
681            case DctConstants.APN_FOTA_ID:
682                return PhoneConstants.APN_TYPE_FOTA;
683            case DctConstants.APN_CBS_ID:
684                return PhoneConstants.APN_TYPE_CBS;
685            case DctConstants.APN_IA_ID:
686                return PhoneConstants.APN_TYPE_IA;
687            case DctConstants.APN_EMERGENCY_ID:
688                return PhoneConstants.APN_TYPE_EMERGENCY;
689            default:
690                Rlog.d(SLOG_TAG, "Unknown id (" + id + ") in apnIdToType");
691                return PhoneConstants.APN_TYPE_DEFAULT;
692        }
693    }
694
695    @Override
696    public synchronized String toString() {
697        // We don't print mDataConnection because its recursive.
698        return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" +
699                mRetryManager.getWaitingApns() + "}" + " mApnSetting={" + mApnSetting +
700                "} mReason=" + mReason + " mDataEnabled=" + mDataEnabled + " mDependencyMet=" +
701                mDependencyMet + "}";
702    }
703
704    private void log(String s) {
705        Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s);
706    }
707
708    public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
709        final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
710        synchronized (mRefCountLock) {
711            pw.println(toString());
712            if (mNetworkRequests.size() > 0) {
713                pw.println("NetworkRequests:");
714                pw.increaseIndent();
715                for (NetworkRequest nr : mNetworkRequests) {
716                    pw.println(nr);
717                }
718                pw.decreaseIndent();
719            }
720            pw.increaseIndent();
721            for (LocalLog l : mLocalLogs) {
722                l.dump(fd, pw, args);
723            }
724            if (mHistoryLogs.size() > 0) pw.println("Historical Logs:");
725            for (LocalLog l : mHistoryLogs) {
726                l.dump(fd, pw, args);
727            }
728            pw.decreaseIndent();
729            pw.println("mRetryManager={" + mRetryManager.toString() + "}");
730        }
731    }
732}
733