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 
17 package com.android.internal.telephony.dataconnection;
18 
19 import android.app.PendingIntent;
20 import android.content.Context;
21 import android.net.NetworkConfig;
22 import android.telephony.Rlog;
23 
24 import com.android.internal.R;
25 import com.android.internal.telephony.DctConstants;
26 import com.android.internal.telephony.Phone;
27 
28 import java.io.FileDescriptor;
29 import java.io.PrintWriter;
30 import java.util.ArrayList;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import java.util.concurrent.atomic.AtomicInteger;
33 
34 /**
35  * Maintain the Apn context
36  */
37 public class ApnContext {
38 
39     public final String LOG_TAG;
40 
41     protected static final boolean DBG = false;
42 
43     private final Context mContext;
44 
45     private final String mApnType;
46 
47     private DctConstants.State mState;
48 
49     private ArrayList<ApnSetting> mWaitingApns = null;
50 
51     /**
52      * Used to check if conditions (new RAT) are resulting in a new list which warrants a retry.
53      * Set in the last trySetupData call.
54      */
55     private ArrayList<ApnSetting> mOriginalWaitingApns = null;
56 
57     public final int priority;
58 
59     /** A zero indicates that all waiting APNs had a permanent error */
60     private AtomicInteger mWaitingApnsPermanentFailureCountDown;
61 
62     private ApnSetting mApnSetting;
63 
64     DcAsyncChannel mDcAc;
65 
66     String mReason;
67 
68     PendingIntent mReconnectAlarmIntent;
69 
70     /**
71      * user/app requested connection on this APN
72      */
73     AtomicBoolean mDataEnabled;
74 
75     private final Object mRefCountLock = new Object();
76     private int mRefCount = 0;
77 
78     /**
79      * carrier requirements met
80      */
81     AtomicBoolean mDependencyMet;
82 
83     private final DcTrackerBase mDcTracker;
84 
85     /**
86      * Remember this as a change in this value to a more permissive state
87      * should cause us to retry even permanent failures
88      */
89     private boolean mConcurrentVoiceAndDataAllowed;
90 
ApnContext(Context context, String apnType, String logTag, NetworkConfig config, DcTrackerBase tracker)91     public ApnContext(Context context, String apnType, String logTag, NetworkConfig config,
92             DcTrackerBase tracker) {
93         mContext = context;
94         mApnType = apnType;
95         mState = DctConstants.State.IDLE;
96         setReason(Phone.REASON_DATA_ENABLED);
97         mDataEnabled = new AtomicBoolean(false);
98         mDependencyMet = new AtomicBoolean(config.dependencyMet);
99         mWaitingApnsPermanentFailureCountDown = new AtomicInteger(0);
100         priority = config.priority;
101         LOG_TAG = logTag;
102         mDcTracker = tracker;
103     }
104 
getApnType()105     public String getApnType() {
106         return mApnType;
107     }
108 
getDcAc()109     public synchronized DcAsyncChannel getDcAc() {
110         return mDcAc;
111     }
112 
setDataConnectionAc(DcAsyncChannel dcac)113     public synchronized void setDataConnectionAc(DcAsyncChannel dcac) {
114         if (DBG) {
115             log("setDataConnectionAc: old dcac=" + mDcAc + " new dcac=" + dcac
116                     + " this=" + this);
117         }
118         mDcAc = dcac;
119     }
120 
getReconnectIntent()121     public synchronized PendingIntent getReconnectIntent() {
122         return mReconnectAlarmIntent;
123     }
124 
setReconnectIntent(PendingIntent intent)125     public synchronized void setReconnectIntent(PendingIntent intent) {
126         mReconnectAlarmIntent = intent;
127     }
128 
getApnSetting()129     public synchronized ApnSetting getApnSetting() {
130         log("getApnSetting: apnSetting=" + mApnSetting);
131         return mApnSetting;
132     }
133 
setApnSetting(ApnSetting apnSetting)134     public synchronized void setApnSetting(ApnSetting apnSetting) {
135         log("setApnSetting: apnSetting=" + apnSetting);
136         mApnSetting = apnSetting;
137     }
138 
setWaitingApns(ArrayList<ApnSetting> waitingApns)139     public synchronized void setWaitingApns(ArrayList<ApnSetting> waitingApns) {
140         mWaitingApns = waitingApns;
141         mOriginalWaitingApns = new ArrayList<ApnSetting>(waitingApns);
142         mWaitingApnsPermanentFailureCountDown.set(mWaitingApns.size());
143     }
144 
getWaitingApnsPermFailCount()145     public int getWaitingApnsPermFailCount() {
146         return mWaitingApnsPermanentFailureCountDown.get();
147     }
148 
decWaitingApnsPermFailCount()149     public void decWaitingApnsPermFailCount() {
150         mWaitingApnsPermanentFailureCountDown.decrementAndGet();
151     }
152 
getNextWaitingApn()153     public synchronized ApnSetting getNextWaitingApn() {
154         ArrayList<ApnSetting> list = mWaitingApns;
155         ApnSetting apn = null;
156 
157         if (list != null) {
158             if (!list.isEmpty()) {
159                 apn = list.get(0);
160             }
161         }
162         return apn;
163     }
164 
removeWaitingApn(ApnSetting apn)165     public synchronized void removeWaitingApn(ApnSetting apn) {
166         if (mWaitingApns != null) {
167             mWaitingApns.remove(apn);
168         }
169     }
170 
getOriginalWaitingApns()171     public synchronized ArrayList<ApnSetting> getOriginalWaitingApns() {
172         return mOriginalWaitingApns;
173     }
174 
getWaitingApns()175     public synchronized ArrayList<ApnSetting> getWaitingApns() {
176         return mWaitingApns;
177     }
178 
setConcurrentVoiceAndDataAllowed(boolean allowed)179     public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) {
180         mConcurrentVoiceAndDataAllowed = allowed;
181     }
182 
isConcurrentVoiceAndDataAllowed()183     public synchronized boolean isConcurrentVoiceAndDataAllowed() {
184         return mConcurrentVoiceAndDataAllowed;
185     }
186 
setState(DctConstants.State s)187     public synchronized void setState(DctConstants.State s) {
188         if (DBG) {
189             log("setState: " + s + ", previous state:" + mState);
190         }
191 
192         mState = s;
193 
194         if (mState == DctConstants.State.FAILED) {
195             if (mWaitingApns != null) {
196                 mWaitingApns.clear(); // when teardown the connection and set to IDLE
197             }
198         }
199     }
200 
getState()201     public synchronized DctConstants.State getState() {
202         return mState;
203     }
204 
isDisconnected()205     public boolean isDisconnected() {
206         DctConstants.State currentState = getState();
207         return ((currentState == DctConstants.State.IDLE) ||
208                     currentState == DctConstants.State.FAILED);
209     }
210 
setReason(String reason)211     public synchronized void setReason(String reason) {
212         if (DBG) {
213             log("set reason as " + reason + ",current state " + mState);
214         }
215         mReason = reason;
216     }
217 
getReason()218     public synchronized String getReason() {
219         return mReason;
220     }
221 
isReady()222     public boolean isReady() {
223         return mDataEnabled.get() && mDependencyMet.get();
224     }
225 
isConnectable()226     public boolean isConnectable() {
227         return isReady() && ((mState == DctConstants.State.IDLE)
228                                 || (mState == DctConstants.State.SCANNING)
229                                 || (mState == DctConstants.State.RETRYING)
230                                 || (mState == DctConstants.State.FAILED));
231     }
232 
isConnectedOrConnecting()233     public boolean isConnectedOrConnecting() {
234         return isReady() && ((mState == DctConstants.State.CONNECTED)
235                                 || (mState == DctConstants.State.CONNECTING)
236                                 || (mState == DctConstants.State.SCANNING)
237                                 || (mState == DctConstants.State.RETRYING));
238     }
239 
setEnabled(boolean enabled)240     public void setEnabled(boolean enabled) {
241         if (DBG) {
242             log("set enabled as " + enabled + ", current state is " + mDataEnabled.get());
243         }
244         mDataEnabled.set(enabled);
245     }
246 
isEnabled()247     public boolean isEnabled() {
248         return mDataEnabled.get();
249     }
250 
setDependencyMet(boolean met)251     public void setDependencyMet(boolean met) {
252         if (DBG) {
253             log("set mDependencyMet as " + met + " current state is " + mDependencyMet.get());
254         }
255         mDependencyMet.set(met);
256     }
257 
getDependencyMet()258     public boolean getDependencyMet() {
259        return mDependencyMet.get();
260     }
261 
isProvisioningApn()262     public boolean isProvisioningApn() {
263         String provisioningApn = mContext.getResources()
264                 .getString(R.string.mobile_provisioning_apn);
265         if ((mApnSetting != null) && (mApnSetting.apn != null)) {
266             return (mApnSetting.apn.equals(provisioningApn));
267         } else {
268             return false;
269         }
270     }
271 
incRefCount()272     public void incRefCount() {
273         synchronized (mRefCountLock) {
274             if (mRefCount++ == 0) {
275                 mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), true);
276             }
277         }
278     }
279 
decRefCount()280     public void decRefCount() {
281         synchronized (mRefCountLock) {
282             if (mRefCount-- == 1) {
283                 mDcTracker.setEnabled(mDcTracker.apnTypeToId(mApnType), false);
284             }
285         }
286     }
287 
288     @Override
toString()289     public synchronized String toString() {
290         // We don't print mDataConnection because its recursive.
291         return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" + mWaitingApns +
292                 "} mWaitingApnsPermanentFailureCountDown=" + mWaitingApnsPermanentFailureCountDown +
293                 " mApnSetting={" + mApnSetting + "} mReason=" + mReason +
294                 " mDataEnabled=" + mDataEnabled + " mDependencyMet=" + mDependencyMet + "}";
295     }
296 
log(String s)297     protected void log(String s) {
298         Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s);
299     }
300 
dump(FileDescriptor fd, PrintWriter pw, String[] args)301     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
302         pw.println("ApnContext: " + this.toString());
303     }
304 }
305