1/*
2 * Copyright (C) 2014 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 static android.telephony.SubscriptionManager.DEFAULT_PHONE_INDEX;
20import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX;
21
22import android.content.Context;
23import android.database.ContentObserver;
24import android.net.ConnectivityManager;
25import android.net.NetworkCapabilities;
26import android.net.NetworkFactory;
27import android.net.NetworkRequest;
28import android.os.AsyncResult;
29import android.os.Handler;
30import android.os.Looper;
31import android.os.Message;
32import android.os.Messenger;
33import android.provider.Settings;
34import android.telephony.Rlog;
35import android.telephony.SubscriptionManager;
36import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
37import android.text.TextUtils;
38import android.util.LocalLog;
39import android.util.SparseArray;
40
41import com.android.internal.telephony.Phone;
42import com.android.internal.telephony.PhoneBase;
43import com.android.internal.telephony.PhoneConstants;
44import com.android.internal.telephony.PhoneProxy;
45import com.android.internal.telephony.SubscriptionController;
46import com.android.internal.telephony.dataconnection.DcSwitchAsyncChannel.RequestInfo;
47import com.android.internal.util.AsyncChannel;
48import com.android.internal.util.IndentingPrintWriter;
49
50import java.io.FileDescriptor;
51import java.io.PrintWriter;
52import java.util.ArrayDeque;
53import java.util.HashMap;
54import java.util.Iterator;
55import java.util.Map.Entry;
56
57public class DctController extends Handler {
58    private static final String LOG_TAG = "DctController";
59    private static final boolean DBG = true;
60
61    private static final int EVENT_PROCESS_REQUESTS = 100;
62    private static final int EVENT_EXECUTE_REQUEST = 101;
63    private static final int EVENT_EXECUTE_ALL_REQUESTS = 102;
64    private static final int EVENT_RELEASE_REQUEST = 103;
65    private static final int EVENT_RELEASE_ALL_REQUESTS = 104;
66    private static final int EVENT_RETRY_ATTACH = 105;
67    private static final int EVENT_SETTINGS_CHANGED = 106;
68    private static final int EVENT_SUBSCRIPTIONS_CHANGED = 107;
69
70    private static final int EVENT_DATA_ATTACHED = 500;
71    private static final int EVENT_DATA_DETACHED = 600;
72    private static final int EVENT_EMERGENCY_CALL_TOGGLED = 700;
73
74    private static DctController sDctController;
75
76    private int mPhoneNum;
77    private PhoneProxy[] mPhones;
78    private DcSwitchStateMachine[] mDcSwitchStateMachine;
79    private DcSwitchAsyncChannel[] mDcSwitchAsyncChannel;
80    private Handler[] mDcSwitchStateHandler;
81    private HashMap<Integer, RequestInfo> mRequestInfos = new HashMap<Integer, RequestInfo>();
82    private Context mContext;
83
84    /** Used to send us NetworkRequests from ConnectivityService.  Remember it so we can
85     * unregister on dispose. */
86    private Messenger[] mNetworkFactoryMessenger;
87    private NetworkFactory[] mNetworkFactory;
88    private NetworkCapabilities[] mNetworkFilter;
89
90    private SubscriptionController mSubController = SubscriptionController.getInstance();
91
92    private SubscriptionManager mSubMgr;
93
94    private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
95            new OnSubscriptionsChangedListener() {
96        @Override
97        public void onSubscriptionsChanged() {
98            DctController.this.obtainMessage(EVENT_SUBSCRIPTIONS_CHANGED).sendToTarget();
99        }
100    };
101
102    private ContentObserver mObserver = new ContentObserver(new Handler()) {
103        @Override
104        public void onChange(boolean selfChange) {
105            logd("Settings change");
106            DctController.this.obtainMessage(EVENT_SETTINGS_CHANGED).sendToTarget();
107        }
108    };
109
110    public void updatePhoneObject(PhoneProxy phone) {
111        if (phone == null) {
112            loge("updatePhoneObject phone = null");
113            return;
114        }
115
116        PhoneBase phoneBase = (PhoneBase)phone.getActivePhone();
117        if (phoneBase == null) {
118            loge("updatePhoneObject phoneBase = null");
119            return;
120        }
121
122        for (int i = 0; i < mPhoneNum; i++) {
123            if (mPhones[i] == phone) {
124                updatePhoneBaseForIndex(i, phoneBase);
125                break;
126            }
127        }
128    }
129
130    private void updatePhoneBaseForIndex(int index, PhoneBase phoneBase) {
131        logd("updatePhoneBaseForIndex for phone index=" + index);
132
133        phoneBase.getServiceStateTracker().registerForDataConnectionAttached(mRspHandler,
134                   EVENT_DATA_ATTACHED + index, null);
135        phoneBase.getServiceStateTracker().registerForDataConnectionDetached(mRspHandler,
136                   EVENT_DATA_DETACHED + index, null);
137        phoneBase.registerForEmergencyCallToggle(mRspHandler,
138                EVENT_EMERGENCY_CALL_TOGGLED + index, null);
139
140        ConnectivityManager cm = (ConnectivityManager)mPhones[index].getContext()
141            .getSystemService(Context.CONNECTIVITY_SERVICE);
142
143        if (mNetworkFactoryMessenger != null) {
144            logd("unregister TelephonyNetworkFactory for phone index=" + index);
145            cm.unregisterNetworkFactory(mNetworkFactoryMessenger[index]);
146            mNetworkFactoryMessenger[index] = null;
147            mNetworkFactory[index] = null;
148            mNetworkFilter[index] = null;
149        }
150
151        // TODO - just make this a singleton.  It'll be simpler
152        mNetworkFilter[index] = new NetworkCapabilities();
153        mNetworkFilter[index].addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
154        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
155        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
156        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
157        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
158        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
159        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
160        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
161        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
162        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
163        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
164        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
165        mNetworkFilter[index].addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
166
167        mNetworkFactory[index] = new TelephonyNetworkFactory(this.getLooper(),
168                mPhones[index].getContext(), "TelephonyNetworkFactory", phoneBase,
169                mNetworkFilter[index]);
170        mNetworkFactory[index].setScoreFilter(50);
171        mNetworkFactoryMessenger[index] = new Messenger(mNetworkFactory[index]);
172        cm.registerNetworkFactory(mNetworkFactoryMessenger[index], "Telephony");
173    }
174
175    private Handler mRspHandler = new Handler() {
176        @Override
177        public void handleMessage(Message msg){
178            if (msg.what >= EVENT_EMERGENCY_CALL_TOGGLED) {
179                logd("EVENT_PHONE" + (msg.what - EVENT_EMERGENCY_CALL_TOGGLED + 1)
180                        + "_EMERGENCY_CALL_END.");
181                AsyncResult ar = (AsyncResult) msg.obj;
182                Integer toggle = (Integer) ar.result;
183                mDcSwitchAsyncChannel[msg.what - EVENT_EMERGENCY_CALL_TOGGLED].
184                        notifyEmergencyCallToggled(toggle.intValue());
185            } else if (msg.what >= EVENT_DATA_DETACHED) {
186                logd("EVENT_PHONE" + (msg.what - EVENT_DATA_DETACHED + 1)
187                        + "_DATA_DETACH.");
188                mDcSwitchAsyncChannel[msg.what - EVENT_DATA_DETACHED].notifyDataDetached();
189
190            } else if (msg.what >= EVENT_DATA_ATTACHED) {
191                logd("EVENT_PHONE" + (msg.what - EVENT_DATA_ATTACHED + 1)
192                        + "_DATA_ATTACH.");
193                mDcSwitchAsyncChannel[msg.what - EVENT_DATA_ATTACHED].notifyDataAttached();
194            }
195        }
196    };
197
198    public static DctController getInstance() {
199       if (sDctController == null) {
200        throw new RuntimeException(
201            "DctController.getInstance can't be called before makeDCTController()");
202        }
203       return sDctController;
204    }
205
206    public static DctController makeDctController(PhoneProxy[] phones) {
207        if (sDctController == null) {
208            logd("makeDctController: new DctController phones.length=" + phones.length);
209            sDctController = new DctController(phones);
210        }
211        logd("makeDctController: X sDctController=" + sDctController);
212        return sDctController;
213    }
214
215    private DctController(PhoneProxy[] phones) {
216        logd("DctController(): phones.length=" + phones.length);
217        if (phones == null || phones.length == 0) {
218            if (phones == null) {
219                loge("DctController(phones): UNEXPECTED phones=null, ignore");
220            } else {
221                loge("DctController(phones): UNEXPECTED phones.length=0, ignore");
222            }
223            return;
224        }
225        mPhoneNum = phones.length;
226        mPhones = phones;
227
228        mDcSwitchStateMachine = new DcSwitchStateMachine[mPhoneNum];
229        mDcSwitchAsyncChannel = new DcSwitchAsyncChannel[mPhoneNum];
230        mDcSwitchStateHandler = new Handler[mPhoneNum];
231        mNetworkFactoryMessenger = new Messenger[mPhoneNum];
232        mNetworkFactory = new NetworkFactory[mPhoneNum];
233        mNetworkFilter = new NetworkCapabilities[mPhoneNum];
234
235        for (int i = 0; i < mPhoneNum; ++i) {
236            int phoneId = i;
237            mDcSwitchStateMachine[i] = new DcSwitchStateMachine(mPhones[i],
238                    "DcSwitchStateMachine-" + phoneId, phoneId);
239            mDcSwitchStateMachine[i].start();
240            mDcSwitchAsyncChannel[i] = new DcSwitchAsyncChannel(mDcSwitchStateMachine[i], phoneId);
241            mDcSwitchStateHandler[i] = new Handler();
242
243            int status = mDcSwitchAsyncChannel[i].fullyConnectSync(mPhones[i].getContext(),
244                mDcSwitchStateHandler[i], mDcSwitchStateMachine[i].getHandler());
245
246            if (status == AsyncChannel.STATUS_SUCCESSFUL) {
247                logd("DctController(phones): Connect success: " + i);
248            } else {
249                loge("DctController(phones): Could not connect to " + i);
250            }
251
252            // Register for radio state change
253            PhoneBase phoneBase = (PhoneBase)mPhones[i].getActivePhone();
254            updatePhoneBaseForIndex(i, phoneBase);
255        }
256
257        mContext = mPhones[0].getContext();
258        mSubMgr = SubscriptionManager.from(mContext);
259        mSubMgr.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
260
261        //Register for settings change.
262        mContext.getContentResolver().registerContentObserver(
263                Settings.Global.getUriFor(
264                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION),
265                false, mObserver);
266    }
267
268    public void dispose() {
269        logd("DctController.dispose");
270        for (int i = 0; i < mPhoneNum; ++i) {
271            ConnectivityManager cm = (ConnectivityManager)mPhones[i].getContext()
272                .getSystemService(Context.CONNECTIVITY_SERVICE);
273            cm.unregisterNetworkFactory(mNetworkFactoryMessenger[i]);
274            mNetworkFactoryMessenger[i] = null;
275        }
276
277        mSubMgr.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
278        mContext.getContentResolver().unregisterContentObserver(mObserver);
279    }
280
281
282    @Override
283    public void handleMessage (Message msg) {
284        logd("handleMessage msg=" + msg);
285        switch (msg.what) {
286            case EVENT_PROCESS_REQUESTS:
287                onProcessRequest();
288                break;
289            case EVENT_EXECUTE_REQUEST:
290                onExecuteRequest((RequestInfo)msg.obj);
291                break;
292            case EVENT_EXECUTE_ALL_REQUESTS:
293                onExecuteAllRequests(msg.arg1);
294                break;
295            case EVENT_RELEASE_REQUEST:
296                onReleaseRequest((RequestInfo)msg.obj);
297                break;
298            case EVENT_RELEASE_ALL_REQUESTS:
299                onReleaseAllRequests(msg.arg1);
300                break;
301            case EVENT_RETRY_ATTACH:
302                onRetryAttach(msg.arg1);
303                break;
304            case EVENT_SETTINGS_CHANGED:
305                onSettingsChanged();
306                break;
307            case EVENT_SUBSCRIPTIONS_CHANGED:
308                onSubInfoReady();
309                break;
310            default:
311                loge("Un-handled message [" + msg.what + "]");
312        }
313    }
314
315    private int requestNetwork(NetworkRequest request, int priority, LocalLog l) {
316        logd("requestNetwork request=" + request + ", priority=" + priority);
317        l.log("Dctc.requestNetwork, priority=" + priority);
318
319        if (mRequestInfos.containsKey(request.requestId)) {
320            logd("requestNetwork replacing " + mRequestInfos.get(request.requestId));
321            // NOTE: executedPhoneId might be reset
322        }
323
324        RequestInfo requestInfo = new RequestInfo(request, priority, l);
325        mRequestInfos.put(request.requestId, requestInfo);
326        processRequests();
327
328        return PhoneConstants.APN_REQUEST_STARTED;
329    }
330
331    private int releaseNetwork(NetworkRequest request) {
332        RequestInfo requestInfo = mRequestInfos.get(request.requestId);
333        logd("releaseNetwork request=" + request + ", requestInfo=" + requestInfo);
334        if (requestInfo != null) requestInfo.log("DctController.releaseNetwork");
335
336        mRequestInfos.remove(request.requestId);
337        releaseRequest(requestInfo);
338        processRequests();
339        return PhoneConstants.APN_REQUEST_STARTED;
340    }
341
342    void processRequests() {
343        logd("processRequests");
344        sendMessage(obtainMessage(EVENT_PROCESS_REQUESTS));
345    }
346
347    void executeRequest(RequestInfo request) {
348        logd("executeRequest, request= " + request);
349        sendMessage(obtainMessage(EVENT_EXECUTE_REQUEST, request));
350    }
351
352    void executeAllRequests(int phoneId) {
353        logd("executeAllRequests, phone:" + phoneId);
354        sendMessage(obtainMessage(EVENT_EXECUTE_ALL_REQUESTS, phoneId,0));
355    }
356
357    void releaseRequest(RequestInfo request) {
358        logd("releaseRequest, request= " + request);
359        sendMessage(obtainMessage(EVENT_RELEASE_REQUEST, request));
360    }
361
362    void releaseAllRequests(int phoneId) {
363        logd("releaseAllRequests, phone:" + phoneId);
364        sendMessage(obtainMessage(EVENT_RELEASE_ALL_REQUESTS, phoneId, 0));
365    }
366
367    public void retryAttach(int phoneId) {
368        logd("retryAttach, phone:" + phoneId);
369        sendMessage(obtainMessage(EVENT_RETRY_ATTACH, phoneId, 0));
370    }
371
372    private void onProcessRequest() {
373        //process all requests
374        //1. Check all requests and find subscription of the top priority
375        //   request
376        //2. Is current data allowed on the selected subscription
377        //2-1. If yes, execute all the requests of the sub
378        //2-2. If no, set data not allow on the current PS subscription
379        //2-2-1. Set data allow on the selected subscription
380
381        final int requestedPhoneId = getTopPriorityRequestPhoneId();
382        int activePhoneId = INVALID_PHONE_INDEX;
383
384        for (int i=0; i<mDcSwitchStateMachine.length; i++) {
385            if (!mDcSwitchAsyncChannel[i].isIdleSync()) {
386                activePhoneId = i;
387                break;
388            }
389        }
390
391        logd("onProcessRequest requestedPhoneId=" + requestedPhoneId
392                + ", activePhoneId=" + activePhoneId);
393
394        if (requestedPhoneId == INVALID_PHONE_INDEX) {
395            // either we have no network request
396            // or there is no valid subscription at the moment
397            if (activePhoneId != INVALID_PHONE_INDEX) {
398                // detatch so we can try connecting later
399                mDcSwitchAsyncChannel[activePhoneId].disconnectAll();
400            }
401            return;
402        }
403
404        // if we have no active phones or the active phone is the desired, make requests
405        if (activePhoneId == INVALID_PHONE_INDEX || activePhoneId == requestedPhoneId) {
406            Iterator<Integer> iterator = mRequestInfos.keySet().iterator();
407            while (iterator.hasNext()) {
408                RequestInfo requestInfo = mRequestInfos.get(iterator.next());
409                if (requestInfo.executedPhoneId != INVALID_PHONE_INDEX) continue;
410                if (getRequestPhoneId(requestInfo.request) == requestedPhoneId) {
411                    mDcSwitchAsyncChannel[requestedPhoneId].connect(requestInfo);
412                }
413            }
414        } else {
415            // otherwise detatch so we can try connecting to the high-priority phone
416            mDcSwitchAsyncChannel[activePhoneId].disconnectAll();
417        }
418    }
419
420    private void onExecuteRequest(RequestInfo requestInfo) {
421        if (requestInfo.executedPhoneId == INVALID_PHONE_INDEX &&
422                mRequestInfos.containsKey(requestInfo.request.requestId)) {
423            logd("onExecuteRequest request=" + requestInfo);
424            requestInfo.log("DctController.onExecuteRequest");
425            String apn = apnForNetworkRequest(requestInfo.request);
426            final int phoneId = getRequestPhoneId(requestInfo.request);
427            requestInfo.executedPhoneId = phoneId;
428            PhoneBase phoneBase = (PhoneBase)mPhones[phoneId].getActivePhone();
429            DcTrackerBase dcTracker = phoneBase.mDcTracker;
430            dcTracker.incApnRefCount(apn, requestInfo.getLog());
431        }
432    }
433
434    private void onExecuteAllRequests(int phoneId) {
435        logd("onExecuteAllRequests phoneId=" + phoneId);
436        Iterator<Integer> iterator = mRequestInfos.keySet().iterator();
437        while (iterator.hasNext()) {
438            RequestInfo requestInfo = mRequestInfos.get(iterator.next());
439            if (getRequestPhoneId(requestInfo.request) == phoneId) {
440                onExecuteRequest(requestInfo);
441            }
442        }
443    }
444
445    private void onReleaseRequest(RequestInfo requestInfo) {
446        logd("onReleaseRequest request=" + requestInfo);
447        if (requestInfo != null) {
448            requestInfo.log("DctController.onReleaseRequest");
449            if (requestInfo.executedPhoneId != INVALID_PHONE_INDEX) {
450                String apn = apnForNetworkRequest(requestInfo.request);
451                int phoneId = requestInfo.executedPhoneId;
452                requestInfo.executedPhoneId = INVALID_PHONE_INDEX;
453                PhoneBase phoneBase = (PhoneBase)mPhones[phoneId].getActivePhone();
454                DcTrackerBase dcTracker = phoneBase.mDcTracker;
455                dcTracker.decApnRefCount(apn, requestInfo.getLog());
456            }
457        }
458    }
459
460    private void onReleaseAllRequests(int phoneId) {
461        logd("onReleaseAllRequests phoneId=" + phoneId);
462        Iterator<Integer> iterator = mRequestInfos.keySet().iterator();
463        while (iterator.hasNext()) {
464            RequestInfo requestInfo = mRequestInfos.get(iterator.next());
465            if (requestInfo.executedPhoneId == phoneId) {
466                onReleaseRequest(requestInfo);
467            }
468        }
469    }
470
471    private void onRetryAttach(int phoneId) {
472        final int topPriPhone = getTopPriorityRequestPhoneId();
473        logd("onRetryAttach phoneId=" + phoneId + " topPri phone = " + topPriPhone);
474
475        if (phoneId != INVALID_PHONE_INDEX && phoneId == topPriPhone) {
476            mDcSwitchAsyncChannel[phoneId].retryConnect();
477        }
478    }
479
480    private void onSettingsChanged() {
481        //Sub Selection
482        long dataSubId = mSubController.getDefaultDataSubId();
483
484        int activePhoneId = -1;
485        for (int i=0; i<mDcSwitchStateMachine.length; i++) {
486            if (!mDcSwitchAsyncChannel[i].isIdleSync()) {
487                activePhoneId = i;
488                break;
489            }
490        }
491
492        int[] subIds = SubscriptionManager.getSubId(activePhoneId);
493        if (subIds ==  null || subIds.length == 0) {
494            loge("onSettingsChange, subIds null or length 0 for activePhoneId " + activePhoneId);
495            return;
496        }
497        logd("onSettingsChange, data sub: " + dataSubId + ", active data sub: " + subIds[0]);
498
499        if (subIds[0] != dataSubId) {
500            Iterator<Integer> iterator = mRequestInfos.keySet().iterator();
501            while (iterator.hasNext()) {
502                RequestInfo requestInfo = mRequestInfos.get(iterator.next());
503                String specifier = requestInfo.request.networkCapabilities.getNetworkSpecifier();
504                if (specifier == null || specifier.equals("")) {
505                    onReleaseRequest(requestInfo);
506                }
507            }
508        }
509
510        // Some request maybe pending due to invalid settings
511        // Try to handle pending request when settings changed
512        for (int i = 0; i < mPhoneNum; ++i) {
513            ((DctController.TelephonyNetworkFactory)mNetworkFactory[i]).evalPendingRequest();
514        }
515
516        processRequests();
517    }
518
519    private int getTopPriorityRequestPhoneId() {
520        String topSubId = null;
521        int priority = -1;
522        int subId;
523
524        for (RequestInfo requestInfo : mRequestInfos.values()) {
525            logd("getTopPriorityRequestPhoneId requestInfo=" + requestInfo);
526            if (requestInfo.priority > priority) {
527                priority = requestInfo.priority;
528                topSubId = requestInfo.request.networkCapabilities.getNetworkSpecifier();
529            }
530        }
531        if (TextUtils.isEmpty(topSubId)) {
532            subId = mSubController.getDefaultDataSubId();
533        } else {
534            subId = Integer.parseInt(topSubId);
535        }
536        final int phoneId = mSubController.getPhoneId(subId);
537        if (phoneId == DEFAULT_PHONE_INDEX) {
538            // that means there isn't a phone for the default sub
539            return INVALID_PHONE_INDEX;
540        }
541        return phoneId;
542    }
543
544    private void onSubInfoReady() {
545        logd("onSubInfoReady mPhoneNum=" + mPhoneNum);
546        for (int i = 0; i < mPhoneNum; ++i) {
547            int subId = mPhones[i].getSubId();
548            logd("onSubInfoReady handle pending requests subId=" + subId);
549            mNetworkFilter[i].setNetworkSpecifier(String.valueOf(subId));
550            ((DctController.TelephonyNetworkFactory)mNetworkFactory[i]).evalPendingRequest();
551        }
552        processRequests();
553    }
554
555    private String apnForNetworkRequest(NetworkRequest nr) {
556        NetworkCapabilities nc = nr.networkCapabilities;
557        // For now, ignore the bandwidth stuff
558        if (nc.getTransportTypes().length > 0 &&
559                nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false) {
560            return null;
561        }
562
563        // in the near term just do 1-1 matches.
564        // TODO - actually try to match the set of capabilities
565        int type = -1;
566        String name = null;
567
568        boolean error = false;
569        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
570            if (name != null) error = true;
571            name = PhoneConstants.APN_TYPE_DEFAULT;
572            type = ConnectivityManager.TYPE_MOBILE;
573        }
574        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
575            if (name != null) error = true;
576            name = PhoneConstants.APN_TYPE_MMS;
577            type = ConnectivityManager.TYPE_MOBILE_MMS;
578        }
579        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
580            if (name != null) error = true;
581            name = PhoneConstants.APN_TYPE_SUPL;
582            type = ConnectivityManager.TYPE_MOBILE_SUPL;
583        }
584        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
585            if (name != null) error = true;
586            name = PhoneConstants.APN_TYPE_DUN;
587            type = ConnectivityManager.TYPE_MOBILE_DUN;
588        }
589        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
590            if (name != null) error = true;
591            name = PhoneConstants.APN_TYPE_FOTA;
592            type = ConnectivityManager.TYPE_MOBILE_FOTA;
593        }
594        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
595            if (name != null) error = true;
596            name = PhoneConstants.APN_TYPE_IMS;
597            type = ConnectivityManager.TYPE_MOBILE_IMS;
598        }
599        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
600            if (name != null) error = true;
601            name = PhoneConstants.APN_TYPE_CBS;
602            type = ConnectivityManager.TYPE_MOBILE_CBS;
603        }
604        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) {
605            if (name != null) error = true;
606            name = PhoneConstants.APN_TYPE_IA;
607            type = ConnectivityManager.TYPE_MOBILE_IA;
608        }
609        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_RCS)) {
610            if (name != null) error = true;
611            name = null;
612            loge("RCS APN type not yet supported");
613        }
614        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) {
615            if (name != null) error = true;
616            name = null;
617            loge("XCAP APN type not yet supported");
618        }
619        if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
620            if (name != null) error = true;
621            name = PhoneConstants.APN_TYPE_EMERGENCY;
622            type = ConnectivityManager.TYPE_MOBILE_EMERGENCY;
623        }
624        if (error) {
625            // TODO: If this error condition is removed, the framework's handling of
626            // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for
627            // say FOTA and INTERNET are marked as restricted.  This is not how
628            // NetworkCapabilities.maybeMarkCapabilitiesRestricted currently works.
629            loge("Multiple apn types specified in request - result is unspecified!");
630        }
631        if (type == -1 || name == null) {
632            loge("Unsupported NetworkRequest in Telephony: nr=" + nr);
633            return null;
634        }
635        return name;
636    }
637
638    private int getRequestPhoneId(NetworkRequest networkRequest) {
639        String specifier = networkRequest.networkCapabilities.getNetworkSpecifier();
640        int subId;
641        if (specifier == null || specifier.equals("")) {
642            subId = mSubController.getDefaultDataSubId();
643        } else {
644            subId = Integer.parseInt(specifier);
645        }
646        int phoneId = mSubController.getPhoneId(subId);
647        return phoneId;
648    }
649
650    private static void logd(String s) {
651        if (DBG) Rlog.d(LOG_TAG, s);
652    }
653
654    private static void loge(String s) {
655        if (DBG) Rlog.e(LOG_TAG, s);
656    }
657
658    private class TelephonyNetworkFactory extends NetworkFactory {
659        private final SparseArray<NetworkRequest> mPendingReq = new SparseArray<NetworkRequest>();
660        private Phone mPhone;
661
662        private class RequestLogger {
663            public NetworkRequest request;
664            public LocalLog log;
665
666            public RequestLogger(NetworkRequest r, LocalLog log) {
667                request = r;
668                this.log = log;
669            }
670        }
671
672        private static final int MAX_REQUESTS_LOGGED = 20;
673        private static final int MAX_LOG_LINES_PER_REQUEST = 50;
674
675        private ArrayDeque<RequestLogger> mRequestLogs = new ArrayDeque<RequestLogger>();
676
677        public TelephonyNetworkFactory(Looper l, Context c, String TAG, Phone phone,
678                NetworkCapabilities nc) {
679            super(l, c, TAG, nc);
680            mPhone = phone;
681            log("NetworkCapabilities: " + nc);
682        }
683
684        public LocalLog requestLog(int requestId, String l) {
685            synchronized(mRequestLogs) {
686                for (RequestLogger r : mRequestLogs) {
687                    if (r.request.requestId == requestId) {
688                        r.log.log(l);
689                        return r.log;
690                    }
691                }
692            }
693            return null;
694        }
695
696        private LocalLog addLogger(NetworkRequest request) {
697            synchronized(mRequestLogs) {
698                for (RequestLogger r : mRequestLogs) {
699                    if (r.request.requestId == request.requestId) {
700                        return r.log;
701                    }
702                }
703                LocalLog l = new LocalLog(MAX_LOG_LINES_PER_REQUEST);
704                RequestLogger logger = new RequestLogger(request, l);
705                while (mRequestLogs.size() >= MAX_REQUESTS_LOGGED) {
706                    mRequestLogs.removeFirst();
707                }
708                mRequestLogs.addLast(logger);
709                return l;
710            }
711        }
712
713        @Override
714        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
715            // figure out the apn type and enable it
716            log("Cellular needs Network for " + networkRequest);
717
718            final LocalLog l = addLogger(networkRequest);
719
720            if (!SubscriptionManager.isUsableSubIdValue(mPhone.getSubId()) ||
721                    getRequestPhoneId(networkRequest) != mPhone.getPhoneId()) {
722                final String str = "Request not useable, pending request.";
723                log(str);
724                l.log(str);
725                mPendingReq.put(networkRequest.requestId, networkRequest);
726                return;
727            }
728
729            DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;
730            String apn = apnForNetworkRequest(networkRequest);
731            if (dcTracker.isApnSupported(apn)) {
732                requestNetwork(networkRequest, dcTracker.getApnPriority(apn), l);
733            } else {
734                final String str = "Unsupported APN";
735                log(str);
736                l.log(str);
737            }
738        }
739
740        @Override
741        protected void releaseNetworkFor(NetworkRequest networkRequest) {
742            String str = "Cellular releasing Network for ";
743            log(str + networkRequest);
744            final LocalLog l = requestLog(networkRequest.requestId, str);
745
746            if (mPendingReq.get(networkRequest.requestId) != null) {
747                str = "Sub Info has not been ready, remove request.";
748                log(str);
749                if (l != null) l.log(str);
750                mPendingReq.remove(networkRequest.requestId);
751                return;
752            }
753
754            releaseNetwork(networkRequest);
755        }
756
757        @Override
758        protected void log(String s) {
759            if (DBG) Rlog.d(LOG_TAG, "[TNF " + mPhone.getSubId() + "]" + s);
760        }
761
762        public void evalPendingRequest() {
763            log("evalPendingRequest, pending request size is " + mPendingReq.size());
764            int key = 0;
765            for(int i = 0; i < mPendingReq.size(); i++) {
766                key = mPendingReq.keyAt(i);
767                NetworkRequest request = mPendingReq.get(key);
768                log("evalPendingRequest: request = " + request);
769
770                mPendingReq.remove(request.requestId);
771                needNetworkFor(request, 0);
772            }
773        }
774
775        @Override
776        public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
777            super.dump(fd, writer, args);
778            final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
779            pw.increaseIndent();
780            pw.println("Pending Requests:");
781            pw.increaseIndent();
782            for (int i = 0; i < mPendingReq.size(); i++) {
783                NetworkRequest request = mPendingReq.valueAt(i);
784                pw.println(request);
785            }
786            pw.decreaseIndent();
787
788            pw.println("Request History:");
789            pw.increaseIndent();
790            synchronized(mRequestLogs) {
791                for (RequestLogger r : mRequestLogs) {
792                    pw.println(r.request);
793                    pw.increaseIndent();
794                    r.log.dump(fd, pw, args);
795                    pw.decreaseIndent();
796                }
797            }
798            pw.decreaseIndent();
799            pw.decreaseIndent();
800        }
801    }
802
803    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
804        pw.println("DctController:");
805        try {
806            for (DcSwitchStateMachine dssm : mDcSwitchStateMachine) {
807                dssm.dump(fd, pw, args);
808            }
809        } catch (Exception e) {
810            e.printStackTrace();
811        }
812        pw.flush();
813        pw.println("++++++++++++++++++++++++++++++++");
814
815        try {
816            for (Entry<Integer, RequestInfo> entry : mRequestInfos.entrySet()) {
817                pw.println("mRequestInfos[" + entry.getKey() + "]=" + entry.getValue());
818            }
819        } catch (Exception e) {
820            e.printStackTrace();
821        }
822        pw.flush();
823        pw.println("++++++++++++++++++++++++++++++++");
824        pw.flush();
825        pw.println("TelephonyNetworkFactories:");
826        for (NetworkFactory tnf : mNetworkFactory) {
827            tnf.dump(fd, pw, args);
828        }
829        pw.flush();
830        pw.println("++++++++++++++++++++++++++++++++");
831        pw.flush();
832    }
833}
834