1/*
2 * Copyright (C) 2016 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.INVALID_SUBSCRIPTION_ID;
20
21import android.content.Context;
22import android.net.NetworkCapabilities;
23import android.net.NetworkFactory;
24import android.net.NetworkRequest;
25import android.net.StringNetworkSpecifier;
26import android.os.Handler;
27import android.os.Looper;
28import android.os.Message;
29import android.telephony.Rlog;
30import android.util.LocalLog;
31
32import com.android.internal.telephony.PhoneSwitcher;
33import com.android.internal.telephony.SubscriptionController;
34import com.android.internal.telephony.SubscriptionMonitor;
35import com.android.internal.util.IndentingPrintWriter;
36
37import java.io.FileDescriptor;
38import java.io.PrintWriter;
39import java.util.HashMap;
40
41public class TelephonyNetworkFactory extends NetworkFactory {
42    public final String LOG_TAG;
43    protected static final boolean DBG = true;
44
45    private final PhoneSwitcher mPhoneSwitcher;
46    private final SubscriptionController mSubscriptionController;
47    private final SubscriptionMonitor mSubscriptionMonitor;
48    private final DcTracker mDcTracker;
49
50    private final HashMap<NetworkRequest, LocalLog> mDefaultRequests =
51            new HashMap<NetworkRequest, LocalLog>();
52    private final HashMap<NetworkRequest, LocalLog> mSpecificRequests =
53            new HashMap<NetworkRequest, LocalLog>();
54
55    private int mPhoneId;
56    private boolean mIsActive;
57    private boolean mIsDefault;
58    private int mSubscriptionId;
59
60    private final static int TELEPHONY_NETWORK_SCORE = 50;
61
62    private final Handler mInternalHandler;
63    private static final int EVENT_ACTIVE_PHONE_SWITCH          = 1;
64    private static final int EVENT_SUBSCRIPTION_CHANGED         = 2;
65    private static final int EVENT_DEFAULT_SUBSCRIPTION_CHANGED = 3;
66    private static final int EVENT_NETWORK_REQUEST              = 4;
67    private static final int EVENT_NETWORK_RELEASE              = 5;
68
69    public TelephonyNetworkFactory(PhoneSwitcher phoneSwitcher,
70            SubscriptionController subscriptionController, SubscriptionMonitor subscriptionMonitor,
71            Looper looper, Context context, int phoneId, DcTracker dcTracker) {
72        super(looper, context, "TelephonyNetworkFactory[" + phoneId + "]", null);
73        mInternalHandler = new InternalHandler(looper);
74
75        setCapabilityFilter(makeNetworkFilter(subscriptionController, phoneId));
76        setScoreFilter(TELEPHONY_NETWORK_SCORE);
77
78        mPhoneSwitcher = phoneSwitcher;
79        mSubscriptionController = subscriptionController;
80        mSubscriptionMonitor = subscriptionMonitor;
81        mPhoneId = phoneId;
82        LOG_TAG = "TelephonyNetworkFactory[" + phoneId + "]";
83        mDcTracker = dcTracker;
84
85        mIsActive = false;
86        mPhoneSwitcher.registerForActivePhoneSwitch(mPhoneId, mInternalHandler,
87                EVENT_ACTIVE_PHONE_SWITCH, null);
88
89        mSubscriptionId = INVALID_SUBSCRIPTION_ID;
90        mSubscriptionMonitor.registerForSubscriptionChanged(mPhoneId, mInternalHandler,
91                EVENT_SUBSCRIPTION_CHANGED, null);
92
93        mIsDefault = false;
94        mSubscriptionMonitor.registerForDefaultDataSubscriptionChanged(mPhoneId, mInternalHandler,
95                EVENT_DEFAULT_SUBSCRIPTION_CHANGED, null);
96
97        register();
98    }
99
100    private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController,
101            int phoneId) {
102        final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId);
103        return makeNetworkFilter(subscriptionId);
104    }
105
106    private NetworkCapabilities makeNetworkFilter(int subscriptionId) {
107        NetworkCapabilities nc = new NetworkCapabilities();
108        nc.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
109        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
110        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
111        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
112        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA);
113        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
114        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
115        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
116        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS);
117        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP);
118        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
119        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
120        nc.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
121        nc.setNetworkSpecifier(new StringNetworkSpecifier(String.valueOf(subscriptionId)));
122        return nc;
123    }
124
125    private class InternalHandler extends Handler {
126        public InternalHandler(Looper looper) {
127            super(looper);
128        }
129
130        @Override
131        public void handleMessage(Message msg) {
132            switch (msg.what) {
133                case EVENT_ACTIVE_PHONE_SWITCH: {
134                    onActivePhoneSwitch();
135                    break;
136                }
137                case EVENT_SUBSCRIPTION_CHANGED: {
138                    onSubIdChange();
139                    break;
140                }
141                case EVENT_DEFAULT_SUBSCRIPTION_CHANGED: {
142                    onDefaultChange();
143                    break;
144                }
145                case EVENT_NETWORK_REQUEST: {
146                    onNeedNetworkFor(msg);
147                    break;
148                }
149                case EVENT_NETWORK_RELEASE: {
150                    onReleaseNetworkFor(msg);
151                    break;
152                }
153            }
154        }
155    }
156
157    private static final int REQUEST_LOG_SIZE = 40;
158    private static final boolean REQUEST = true;
159    private static final boolean RELEASE = false;
160
161    private void applyRequests(HashMap<NetworkRequest, LocalLog> requestMap, boolean action,
162            String logStr) {
163        for (NetworkRequest networkRequest : requestMap.keySet()) {
164            LocalLog localLog = requestMap.get(networkRequest);
165            localLog.log(logStr);
166            if (action == REQUEST) {
167                mDcTracker.requestNetwork(networkRequest, localLog);
168            } else {
169                mDcTracker.releaseNetwork(networkRequest, localLog);
170            }
171        }
172    }
173
174    // apply or revoke requests if our active-ness changes
175    private void onActivePhoneSwitch() {
176        final boolean newIsActive = mPhoneSwitcher.isPhoneActive(mPhoneId);
177        if (mIsActive != newIsActive) {
178            mIsActive = newIsActive;
179            String logString = "onActivePhoneSwitch(" + mIsActive + ", " + mIsDefault + ")";
180            if (DBG) log(logString);
181            if (mIsDefault) {
182                applyRequests(mDefaultRequests, (mIsActive ? REQUEST : RELEASE), logString);
183            }
184            applyRequests(mSpecificRequests, (mIsActive ? REQUEST : RELEASE), logString);
185        }
186    }
187
188    // watch for phone->subId changes, reapply new filter and let
189    // that flow through to apply/revoke of requests
190    private void onSubIdChange() {
191        final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId(mPhoneId);
192        if (mSubscriptionId != newSubscriptionId) {
193            if (DBG) log("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId);
194            mSubscriptionId = newSubscriptionId;
195            setCapabilityFilter(makeNetworkFilter(mSubscriptionId));
196        }
197    }
198
199    // watch for default-data changes (could be side effect of
200    // phoneId->subId map change or direct change of default subId)
201    // and apply/revoke default-only requests.
202    private void onDefaultChange() {
203        final int newDefaultSubscriptionId = mSubscriptionController.getDefaultDataSubId();
204        final boolean newIsDefault = (newDefaultSubscriptionId == mSubscriptionId);
205        if (newIsDefault != mIsDefault) {
206            mIsDefault = newIsDefault;
207            String logString = "onDefaultChange(" + mIsActive + "," + mIsDefault + ")";
208            if (DBG) log(logString);
209            if (mIsActive == false) return;
210            applyRequests(mDefaultRequests, (mIsDefault ? REQUEST : RELEASE), logString);
211        }
212    }
213
214    @Override
215    public void needNetworkFor(NetworkRequest networkRequest, int score) {
216        Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_REQUEST);
217        msg.obj = networkRequest;
218        msg.sendToTarget();
219    }
220
221    private void onNeedNetworkFor(Message msg) {
222        NetworkRequest networkRequest = (NetworkRequest)msg.obj;
223        boolean isApplicable = false;
224        LocalLog localLog = null;
225        if (networkRequest.networkCapabilities.getNetworkSpecifier() == null) {
226            // request only for the default network
227            localLog = mDefaultRequests.get(networkRequest);
228            if (localLog == null) {
229                localLog = new LocalLog(REQUEST_LOG_SIZE);
230                localLog.log("created for " + networkRequest);
231                mDefaultRequests.put(networkRequest, localLog);
232                isApplicable = mIsDefault;
233            }
234        } else {
235            localLog = mSpecificRequests.get(networkRequest);
236            if (localLog == null) {
237                localLog = new LocalLog(REQUEST_LOG_SIZE);
238                mSpecificRequests.put(networkRequest, localLog);
239                isApplicable = true;
240            }
241        }
242        if (mIsActive && isApplicable) {
243            String s = "onNeedNetworkFor";
244            localLog.log(s);
245            log(s + " " + networkRequest);
246            mDcTracker.requestNetwork(networkRequest, localLog);
247        } else {
248            String s = "not acting - isApp=" + isApplicable + ", isAct=" + mIsActive;
249            localLog.log(s);
250            log(s + " " + networkRequest);
251        }
252    }
253
254    @Override
255    public void releaseNetworkFor(NetworkRequest networkRequest) {
256        Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_RELEASE);
257        msg.obj = networkRequest;
258        msg.sendToTarget();
259    }
260
261    private void onReleaseNetworkFor(Message msg) {
262        NetworkRequest networkRequest = (NetworkRequest)msg.obj;
263        LocalLog localLog = null;
264        boolean isApplicable = false;
265        if (networkRequest.networkCapabilities.getNetworkSpecifier() == null) {
266            // request only for the default network
267            localLog = mDefaultRequests.remove(networkRequest);
268            isApplicable = (localLog != null) && mIsDefault;
269        } else {
270            localLog = mSpecificRequests.remove(networkRequest);
271            isApplicable = (localLog != null);
272        }
273        if (mIsActive && isApplicable) {
274            String s = "onReleaseNetworkFor";
275            localLog.log(s);
276            log(s + " " + networkRequest);
277            mDcTracker.releaseNetwork(networkRequest, localLog);
278        } else {
279            String s = "not releasing - isApp=" + isApplicable + ", isAct=" + mIsActive;
280            localLog.log(s);
281            log(s + " " + networkRequest);
282        }
283    }
284
285    protected void log(String s) {
286        Rlog.d(LOG_TAG, s);
287    }
288
289    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
290        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
291        pw.println(LOG_TAG + " mSubId=" + mSubscriptionId + " mIsActive=" +
292                mIsActive + " mIsDefault=" + mIsDefault);
293        pw.println("Default Requests:");
294        pw.increaseIndent();
295        for (NetworkRequest nr : mDefaultRequests.keySet()) {
296            pw.println(nr);
297            pw.increaseIndent();
298            mDefaultRequests.get(nr).dump(fd, pw, args);
299            pw.decreaseIndent();
300        }
301        pw.decreaseIndent();
302    }
303}
304