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 
17 package com.android.internal.telephony.dataconnection;
18 
19 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
20 
21 import android.content.Context;
22 import android.net.NetworkCapabilities;
23 import android.net.NetworkFactory;
24 import android.net.NetworkRequest;
25 import android.net.StringNetworkSpecifier;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.telephony.Rlog;
30 import android.util.LocalLog;
31 
32 import com.android.internal.telephony.PhoneSwitcher;
33 import com.android.internal.telephony.SubscriptionController;
34 import com.android.internal.telephony.SubscriptionMonitor;
35 import com.android.internal.util.IndentingPrintWriter;
36 
37 import java.io.FileDescriptor;
38 import java.io.PrintWriter;
39 import java.util.HashMap;
40 
41 public 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 
TelephonyNetworkFactory(PhoneSwitcher phoneSwitcher, SubscriptionController subscriptionController, SubscriptionMonitor subscriptionMonitor, Looper looper, Context context, int phoneId, DcTracker dcTracker)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 
makeNetworkFilter(SubscriptionController subscriptionController, int phoneId)100     private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController,
101             int phoneId) {
102         final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId);
103         return makeNetworkFilter(subscriptionId);
104     }
105 
makeNetworkFilter(int subscriptionId)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 {
InternalHandler(Looper looper)126         public InternalHandler(Looper looper) {
127             super(looper);
128         }
129 
130         @Override
handleMessage(Message msg)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 
applyRequests(HashMap<NetworkRequest, LocalLog> requestMap, boolean action, String logStr)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
onActivePhoneSwitch()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
onSubIdChange()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.
onDefaultChange()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
needNetworkFor(NetworkRequest networkRequest, int score)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 
onNeedNetworkFor(Message msg)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
releaseNetworkFor(NetworkRequest networkRequest)255     public void releaseNetworkFor(NetworkRequest networkRequest) {
256         Message msg = mInternalHandler.obtainMessage(EVENT_NETWORK_RELEASE);
257         msg.obj = networkRequest;
258         msg.sendToTarget();
259     }
260 
onReleaseNetworkFor(Message msg)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 
log(String s)285     protected void log(String s) {
286         Rlog.d(LOG_TAG, s);
287     }
288 
dump(FileDescriptor fd, PrintWriter writer, String[] args)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