• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.net.NetworkInfo.DetailedState;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.Messenger;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.telephony.TelephonyManager;
32 import android.text.TextUtils;
33 import android.util.Slog;
34 
35 import com.android.internal.telephony.DctConstants;
36 import com.android.internal.telephony.ITelephony;
37 import com.android.internal.telephony.PhoneConstants;
38 import com.android.internal.telephony.TelephonyIntents;
39 import com.android.internal.util.AsyncChannel;
40 
41 import java.io.CharArrayWriter;
42 import java.io.PrintWriter;
43 
44 /**
45  * Track the state of mobile data connectivity. This is done by
46  * receiving broadcast intents from the Phone process whenever
47  * the state of data connectivity changes.
48  *
49  * {@hide}
50  */
51 public class MobileDataStateTracker implements NetworkStateTracker {
52 
53     private static final String TAG = "MobileDataStateTracker";
54     private static final boolean DBG = false;
55     private static final boolean VDBG = false;
56 
57     private PhoneConstants.DataState mMobileDataState;
58     private ITelephony mPhoneService;
59 
60     private String mApnType;
61     private NetworkInfo mNetworkInfo;
62     private boolean mTeardownRequested = false;
63     private Handler mTarget;
64     private Context mContext;
65     private LinkProperties mLinkProperties;
66     private LinkCapabilities mLinkCapabilities;
67     private boolean mPrivateDnsRouteSet = false;
68     private boolean mDefaultRouteSet = false;
69 
70     // NOTE: these are only kept for debugging output; actual values are
71     // maintained in DataConnectionTracker.
72     protected boolean mUserDataEnabled = true;
73     protected boolean mPolicyDataEnabled = true;
74 
75     private Handler mHandler;
76     private AsyncChannel mDataConnectionTrackerAc;
77     private Messenger mMessenger;
78 
79     /**
80      * Create a new MobileDataStateTracker
81      * @param netType the ConnectivityManager network type
82      * @param tag the name of this network
83      */
MobileDataStateTracker(int netType, String tag)84     public MobileDataStateTracker(int netType, String tag) {
85         mNetworkInfo = new NetworkInfo(netType,
86                 TelephonyManager.getDefault().getNetworkType(), tag,
87                 TelephonyManager.getDefault().getNetworkTypeName());
88         mApnType = networkTypeToApnType(netType);
89     }
90 
91     /**
92      * Begin monitoring data connectivity.
93      *
94      * @param context is the current Android context
95      * @param target is the Hander to which to return the events.
96      */
startMonitoring(Context context, Handler target)97     public void startMonitoring(Context context, Handler target) {
98         mTarget = target;
99         mContext = context;
100 
101         mHandler = new MdstHandler(target.getLooper(), this);
102 
103         IntentFilter filter = new IntentFilter();
104         filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
105         filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
106         filter.addAction(DctConstants.ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
107 
108         mContext.registerReceiver(new MobileDataStateReceiver(), filter);
109         mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
110     }
111 
112     static class MdstHandler extends Handler {
113         private MobileDataStateTracker mMdst;
114 
MdstHandler(Looper looper, MobileDataStateTracker mdst)115         MdstHandler(Looper looper, MobileDataStateTracker mdst) {
116             super(looper);
117             mMdst = mdst;
118         }
119 
120         @Override
handleMessage(Message msg)121         public void handleMessage(Message msg) {
122             switch (msg.what) {
123                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
124                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
125                         if (VDBG) {
126                             mMdst.log("MdstHandler connected");
127                         }
128                         mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
129                     } else {
130                         if (VDBG) {
131                             mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
132                         }
133                     }
134                     break;
135                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
136                     if (VDBG) mMdst.log("Disconnected from DataStateTracker");
137                     mMdst.mDataConnectionTrackerAc = null;
138                     break;
139                 default: {
140                     if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
141                     break;
142                 }
143             }
144         }
145     }
146 
isPrivateDnsRouteSet()147     public boolean isPrivateDnsRouteSet() {
148         return mPrivateDnsRouteSet;
149     }
150 
privateDnsRouteSet(boolean enabled)151     public void privateDnsRouteSet(boolean enabled) {
152         mPrivateDnsRouteSet = enabled;
153     }
154 
getNetworkInfo()155     public NetworkInfo getNetworkInfo() {
156         return mNetworkInfo;
157     }
158 
isDefaultRouteSet()159     public boolean isDefaultRouteSet() {
160         return mDefaultRouteSet;
161     }
162 
defaultRouteSet(boolean enabled)163     public void defaultRouteSet(boolean enabled) {
164         mDefaultRouteSet = enabled;
165     }
166 
167     /**
168      * This is not implemented.
169      */
releaseWakeLock()170     public void releaseWakeLock() {
171     }
172 
173     private class MobileDataStateReceiver extends BroadcastReceiver {
174         @Override
onReceive(Context context, Intent intent)175         public void onReceive(Context context, Intent intent) {
176             if (intent.getAction().equals(TelephonyIntents.
177                     ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
178                 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
179                 if (VDBG) {
180                     log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED"
181                         + "mApnType=%s %s received apnType=%s", mApnType,
182                         TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType));
183                 }
184                 if (!TextUtils.equals(apnType, mApnType)) {
185                     return;
186                 }
187 
188                 int oldSubtype = mNetworkInfo.getSubtype();
189                 int newSubType = TelephonyManager.getDefault().getNetworkType();
190                 String subTypeName = TelephonyManager.getDefault().getNetworkTypeName();
191                 mNetworkInfo.setSubtype(newSubType, subTypeName);
192                 if (newSubType != oldSubtype && mNetworkInfo.isConnected()) {
193                     Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED,
194                                                         oldSubtype, 0, mNetworkInfo);
195                     msg.sendToTarget();
196                 }
197 
198                 PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class,
199                         intent.getStringExtra(PhoneConstants.STATE_KEY));
200                 String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY);
201                 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
202                 mNetworkInfo.setRoaming(intent.getBooleanExtra(
203                         PhoneConstants.DATA_NETWORK_ROAMING_KEY, false));
204                 if (VDBG) {
205                     log(mApnType + " setting isAvailable to " +
206                             intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false));
207                 }
208                 mNetworkInfo.setIsAvailable(!intent.getBooleanExtra(
209                         PhoneConstants.NETWORK_UNAVAILABLE_KEY, false));
210 
211                 if (DBG) {
212                     log("Received state=" + state + ", old=" + mMobileDataState +
213                         ", reason=" + (reason == null ? "(unspecified)" : reason));
214                 }
215                 if (mMobileDataState != state) {
216                     mMobileDataState = state;
217                     switch (state) {
218                         case DISCONNECTED:
219                             if(isTeardownRequested()) {
220                                 setTeardownRequested(false);
221                             }
222 
223                             setDetailedState(DetailedState.DISCONNECTED, reason, apnName);
224                             // can't do this here - ConnectivityService needs it to clear stuff
225                             // it's ok though - just leave it to be refreshed next time
226                             // we connect.
227                             //if (DBG) log("clearing mInterfaceName for "+ mApnType +
228                             //        " as it DISCONNECTED");
229                             //mInterfaceName = null;
230                             break;
231                         case CONNECTING:
232                             setDetailedState(DetailedState.CONNECTING, reason, apnName);
233                             break;
234                         case SUSPENDED:
235                             setDetailedState(DetailedState.SUSPENDED, reason, apnName);
236                             break;
237                         case CONNECTED:
238                             mLinkProperties = intent.getParcelableExtra(
239                                     PhoneConstants.DATA_LINK_PROPERTIES_KEY);
240                             if (mLinkProperties == null) {
241                                 loge("CONNECTED event did not supply link properties.");
242                                 mLinkProperties = new LinkProperties();
243                             }
244                             mLinkCapabilities = intent.getParcelableExtra(
245                                     PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
246                             if (mLinkCapabilities == null) {
247                                 loge("CONNECTED event did not supply link capabilities.");
248                                 mLinkCapabilities = new LinkCapabilities();
249                             }
250                             setDetailedState(DetailedState.CONNECTED, reason, apnName);
251                             break;
252                     }
253                 } else {
254                     // There was no state change. Check if LinkProperties has been updated.
255                     if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
256                         mLinkProperties = intent.getParcelableExtra(
257                                 PhoneConstants.DATA_LINK_PROPERTIES_KEY);
258                         if (mLinkProperties == null) {
259                             loge("No link property in LINK_PROPERTIES change event.");
260                             mLinkProperties = new LinkProperties();
261                         }
262                         // Just update reason field in this NetworkInfo
263                         mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason,
264                                                       mNetworkInfo.getExtraInfo());
265                         Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED,
266                                                             mNetworkInfo);
267                         msg.sendToTarget();
268                     }
269                 }
270             } else if (intent.getAction().
271                     equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
272                 String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
273                 if (!TextUtils.equals(apnType, mApnType)) {
274                     if (DBG) {
275                         log(String.format(
276                                 "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " +
277                                 "mApnType=%s != received apnType=%s", mApnType, apnType));
278                     }
279                     return;
280                 }
281                 String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY);
282                 String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
283                 if (DBG) {
284                     log("Received " + intent.getAction() +
285                                 " broadcast" + reason == null ? "" : "(" + reason + ")");
286                 }
287                 setDetailedState(DetailedState.FAILED, reason, apnName);
288             } else if (intent.getAction().equals(DctConstants
289                     .ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
290                 if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
291                 mMessenger =
292                     intent.getParcelableExtra(DctConstants.EXTRA_MESSENGER);
293                 AsyncChannel ac = new AsyncChannel();
294                 ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
295             } else {
296                 if (DBG) log("Broadcast received: ignore " + intent.getAction());
297             }
298         }
299     }
300 
getPhoneService(boolean forceRefresh)301     private void getPhoneService(boolean forceRefresh) {
302         if ((mPhoneService == null) || forceRefresh) {
303             mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone"));
304         }
305     }
306 
307     /**
308      * Report whether data connectivity is possible.
309      */
isAvailable()310     public boolean isAvailable() {
311         return mNetworkInfo.isAvailable();
312     }
313 
314     /**
315      * Return the system properties name associated with the tcp buffer sizes
316      * for this network.
317      */
getTcpBufferSizesPropName()318     public String getTcpBufferSizesPropName() {
319         String networkTypeStr = "unknown";
320         TelephonyManager tm = new TelephonyManager(mContext);
321         //TODO We have to edit the parameter for getNetworkType regarding CDMA
322         switch(tm.getNetworkType()) {
323         case TelephonyManager.NETWORK_TYPE_GPRS:
324             networkTypeStr = "gprs";
325             break;
326         case TelephonyManager.NETWORK_TYPE_EDGE:
327             networkTypeStr = "edge";
328             break;
329         case TelephonyManager.NETWORK_TYPE_UMTS:
330             networkTypeStr = "umts";
331             break;
332         case TelephonyManager.NETWORK_TYPE_HSDPA:
333             networkTypeStr = "hsdpa";
334             break;
335         case TelephonyManager.NETWORK_TYPE_HSUPA:
336             networkTypeStr = "hsupa";
337             break;
338         case TelephonyManager.NETWORK_TYPE_HSPA:
339             networkTypeStr = "hspa";
340             break;
341         case TelephonyManager.NETWORK_TYPE_HSPAP:
342             networkTypeStr = "hspap";
343             break;
344         case TelephonyManager.NETWORK_TYPE_CDMA:
345             networkTypeStr = "cdma";
346             break;
347         case TelephonyManager.NETWORK_TYPE_1xRTT:
348             networkTypeStr = "1xrtt";
349             break;
350         case TelephonyManager.NETWORK_TYPE_EVDO_0:
351             networkTypeStr = "evdo";
352             break;
353         case TelephonyManager.NETWORK_TYPE_EVDO_A:
354             networkTypeStr = "evdo";
355             break;
356         case TelephonyManager.NETWORK_TYPE_EVDO_B:
357             networkTypeStr = "evdo";
358             break;
359         case TelephonyManager.NETWORK_TYPE_IDEN:
360             networkTypeStr = "iden";
361             break;
362         case TelephonyManager.NETWORK_TYPE_LTE:
363             networkTypeStr = "lte";
364             break;
365         case TelephonyManager.NETWORK_TYPE_EHRPD:
366             networkTypeStr = "ehrpd";
367             break;
368         default:
369             loge("unknown network type: " + tm.getNetworkType());
370         }
371         return "net.tcp.buffersize." + networkTypeStr;
372     }
373 
374     /**
375      * Tear down mobile data connectivity, i.e., disable the ability to create
376      * mobile data connections.
377      * TODO - make async and return nothing?
378      */
teardown()379     public boolean teardown() {
380         setTeardownRequested(true);
381         return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED);
382     }
383 
384     @Override
captivePortalCheckComplete()385     public void captivePortalCheckComplete() {
386         // not implemented
387     }
388 
389     /**
390      * Record the detailed state of a network, and if it is a
391      * change from the previous state, send a notification to
392      * any listeners.
393      * @param state the new {@code DetailedState}
394      * @param reason a {@code String} indicating a reason for the state change,
395      * if one was supplied. May be {@code null}.
396      * @param extraInfo optional {@code String} providing extra information about the state change
397      */
setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo)398     private void setDetailedState(NetworkInfo.DetailedState state, String reason,
399             String extraInfo) {
400         if (DBG) log("setDetailed state, old ="
401                 + mNetworkInfo.getDetailedState() + " and new state=" + state);
402         if (state != mNetworkInfo.getDetailedState()) {
403             boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING);
404             String lastReason = mNetworkInfo.getReason();
405             /*
406              * If a reason was supplied when the CONNECTING state was entered, and no
407              * reason was supplied for entering the CONNECTED state, then retain the
408              * reason that was supplied when going to CONNECTING.
409              */
410             if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null
411                     && lastReason != null)
412                 reason = lastReason;
413             mNetworkInfo.setDetailedState(state, reason, extraInfo);
414             Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo));
415             msg.sendToTarget();
416         }
417     }
418 
setTeardownRequested(boolean isRequested)419     public void setTeardownRequested(boolean isRequested) {
420         mTeardownRequested = isRequested;
421     }
422 
isTeardownRequested()423     public boolean isTeardownRequested() {
424         return mTeardownRequested;
425     }
426 
427     /**
428      * Re-enable mobile data connectivity after a {@link #teardown()}.
429      * TODO - make async and always get a notification?
430      */
reconnect()431     public boolean reconnect() {
432         boolean retValue = false; //connected or expect to be?
433         setTeardownRequested(false);
434         switch (setEnableApn(mApnType, true)) {
435             case PhoneConstants.APN_ALREADY_ACTIVE:
436                 // need to set self to CONNECTING so the below message is handled.
437                 retValue = true;
438                 break;
439             case PhoneConstants.APN_REQUEST_STARTED:
440                 // set IDLE here , avoid the following second FAILED not sent out
441                 mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null);
442                 retValue = true;
443                 break;
444             case PhoneConstants.APN_REQUEST_FAILED:
445             case PhoneConstants.APN_TYPE_NOT_AVAILABLE:
446                 break;
447             default:
448                 loge("Error in reconnect - unexpected response.");
449                 break;
450         }
451         return retValue;
452     }
453 
454     /**
455      * Turn on or off the mobile radio. No connectivity will be possible while the
456      * radio is off. The operation is a no-op if the radio is already in the desired state.
457      * @param turnOn {@code true} if the radio should be turned on, {@code false} if
458      */
setRadio(boolean turnOn)459     public boolean setRadio(boolean turnOn) {
460         getPhoneService(false);
461         /*
462          * If the phone process has crashed in the past, we'll get a
463          * RemoteException and need to re-reference the service.
464          */
465         for (int retry = 0; retry < 2; retry++) {
466             if (mPhoneService == null) {
467                 loge("Ignoring mobile radio request because could not acquire PhoneService");
468                 break;
469             }
470 
471             try {
472                 return mPhoneService.setRadio(turnOn);
473             } catch (RemoteException e) {
474                 if (retry == 0) getPhoneService(true);
475             }
476         }
477 
478         loge("Could not set radio power to " + (turnOn ? "on" : "off"));
479         return false;
480     }
481 
482     @Override
setUserDataEnable(boolean enabled)483     public void setUserDataEnable(boolean enabled) {
484         if (DBG) log("setUserDataEnable: E enabled=" + enabled);
485         final AsyncChannel channel = mDataConnectionTrackerAc;
486         if (channel != null) {
487             channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE,
488                     enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
489             mUserDataEnabled = enabled;
490         }
491         if (VDBG) log("setUserDataEnable: X enabled=" + enabled);
492     }
493 
494     @Override
setPolicyDataEnable(boolean enabled)495     public void setPolicyDataEnable(boolean enabled) {
496         if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")");
497         final AsyncChannel channel = mDataConnectionTrackerAc;
498         if (channel != null) {
499             channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE,
500                     enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
501             mPolicyDataEnabled = enabled;
502         }
503     }
504 
505     /**
506      * carrier dependency is met/unmet
507      * @param met
508      */
setDependencyMet(boolean met)509     public void setDependencyMet(boolean met) {
510         Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType);
511         try {
512             if (DBG) log("setDependencyMet: E met=" + met);
513             Message msg = Message.obtain();
514             msg.what = DctConstants.CMD_SET_DEPENDENCY_MET;
515             msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED);
516             msg.setData(bundle);
517             mDataConnectionTrackerAc.sendMessage(msg);
518             if (VDBG) log("setDependencyMet: X met=" + met);
519         } catch (NullPointerException e) {
520             loge("setDependencyMet: X mAc was null" + e);
521         }
522     }
523 
524     @Override
toString()525     public String toString() {
526         final CharArrayWriter writer = new CharArrayWriter();
527         final PrintWriter pw = new PrintWriter(writer);
528         pw.print("Mobile data state: "); pw.println(mMobileDataState);
529         pw.print("Data enabled: user="); pw.print(mUserDataEnabled);
530         pw.print(", policy="); pw.println(mPolicyDataEnabled);
531         return writer.toString();
532     }
533 
534    /**
535      * Internal method supporting the ENABLE_MMS feature.
536      * @param apnType the type of APN to be enabled or disabled (e.g., mms)
537      * @param enable {@code true} to enable the specified APN type,
538      * {@code false} to disable it.
539      * @return an integer value representing the outcome of the request.
540      */
setEnableApn(String apnType, boolean enable)541     private int setEnableApn(String apnType, boolean enable) {
542         getPhoneService(false);
543         /*
544          * If the phone process has crashed in the past, we'll get a
545          * RemoteException and need to re-reference the service.
546          */
547         for (int retry = 0; retry < 2; retry++) {
548             if (mPhoneService == null) {
549                 loge("Ignoring feature request because could not acquire PhoneService");
550                 break;
551             }
552 
553             try {
554                 if (enable) {
555                     return mPhoneService.enableApnType(apnType);
556                 } else {
557                     return mPhoneService.disableApnType(apnType);
558                 }
559             } catch (RemoteException e) {
560                 if (retry == 0) getPhoneService(true);
561             }
562         }
563 
564         loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
565         return PhoneConstants.APN_REQUEST_FAILED;
566     }
567 
networkTypeToApnType(int netType)568     public static String networkTypeToApnType(int netType) {
569         switch(netType) {
570             case ConnectivityManager.TYPE_MOBILE:
571                 return PhoneConstants.APN_TYPE_DEFAULT;  // TODO - use just one of these
572             case ConnectivityManager.TYPE_MOBILE_MMS:
573                 return PhoneConstants.APN_TYPE_MMS;
574             case ConnectivityManager.TYPE_MOBILE_SUPL:
575                 return PhoneConstants.APN_TYPE_SUPL;
576             case ConnectivityManager.TYPE_MOBILE_DUN:
577                 return PhoneConstants.APN_TYPE_DUN;
578             case ConnectivityManager.TYPE_MOBILE_HIPRI:
579                 return PhoneConstants.APN_TYPE_HIPRI;
580             case ConnectivityManager.TYPE_MOBILE_FOTA:
581                 return PhoneConstants.APN_TYPE_FOTA;
582             case ConnectivityManager.TYPE_MOBILE_IMS:
583                 return PhoneConstants.APN_TYPE_IMS;
584             case ConnectivityManager.TYPE_MOBILE_CBS:
585                 return PhoneConstants.APN_TYPE_CBS;
586             default:
587                 sloge("Error mapping networkType " + netType + " to apnType.");
588                 return null;
589         }
590     }
591 
592     /**
593      * @see android.net.NetworkStateTracker#getLinkProperties()
594      */
getLinkProperties()595     public LinkProperties getLinkProperties() {
596         return new LinkProperties(mLinkProperties);
597     }
598 
599     /**
600      * @see android.net.NetworkStateTracker#getLinkCapabilities()
601      */
getLinkCapabilities()602     public LinkCapabilities getLinkCapabilities() {
603         return new LinkCapabilities(mLinkCapabilities);
604     }
605 
log(String s)606     private void log(String s) {
607         Slog.d(TAG, mApnType + ": " + s);
608     }
609 
loge(String s)610     private void loge(String s) {
611         Slog.e(TAG, mApnType + ": " + s);
612     }
613 
sloge(String s)614     static private void sloge(String s) {
615         Slog.e(TAG, s);
616     }
617 }
618