1 /*
2  * Copyright (C) 2021 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.telephony.qns;
18 
19 import static android.telephony.data.ThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.net.NetworkCapabilities;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.telephony.AccessNetworkConstants;
29 import android.telephony.data.QualifiedNetworksService;
30 import android.telephony.data.ThrottleStatus;
31 import android.util.Log;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 
35 import java.io.FileDescriptor;
36 import java.io.PrintWriter;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 
41 /**
42  * Implementation of the qualified networks service, which is a service providing up-to-date
43  * qualified network information to the frameworks for data handover control. A qualified network is
44  * defined as an access network that is ready for bringing up data connection for given APN types.
45  */
46 public class QualifiedNetworksServiceImpl extends QualifiedNetworksService {
47 
48     static final String LOG_TAG = QualifiedNetworksServiceImpl.class.getSimpleName();
49     private static final boolean DBG = true;
50     private static final int QNS_CONFIGURATION_LOADED = 1;
51     private static final int QUALIFIED_NETWORKS_CHANGED = 2;
52     private static final int QNS_CONFIGURATION_CHANGED = 3;
53     HashMap<Integer, NetworkAvailabilityProviderImpl> mProviderMap = new HashMap<>();
54     HashMap<Integer, HandlerThread> mHandlerThreadMap = new HashMap<>();
55     Context mContext;
56     HandlerThread mHandlerThread;
57     @VisibleForTesting QnsComponents mQnsComponents;
58 
59     /** Default constructor. */
QualifiedNetworksServiceImpl()60     public QualifiedNetworksServiceImpl() {
61         super();
62         log("created QualifiedNetworksServiceImpl.");
63     }
64 
65     /**
66      * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
67      * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
68      * instances. The system will call this method after binding the qualified networks service for
69      * each active SIM slot index.
70      *
71      * @param slotIndex SIM slot index the qualified networks service associated with.
72      * @return Qualified networks service instance
73      */
74     @Override
onCreateNetworkAvailabilityProvider(int slotIndex)75     public NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex) {
76         log("Qualified Networks Service created for slot " + slotIndex);
77         if (!QnsUtils.isValidSlotIndex(mContext, slotIndex)) {
78             log("Invalid slotIndex " + slotIndex + ". fail to create NetworkAvailabilityProvider");
79             return null;
80         }
81         if (!mHandlerThreadMap.containsKey(slotIndex)) {
82             HandlerThread ht = new HandlerThread("NapConfigHandler-" + slotIndex);
83             ht.start();
84             mHandlerThreadMap.put(slotIndex, ht);
85         }
86         NetworkAvailabilityProviderImpl provider = new NetworkAvailabilityProviderImpl(slotIndex);
87         mProviderMap.put(slotIndex, provider);
88         return provider;
89     }
90 
91     @Override
onCreate()92     public void onCreate() {
93         log("onCreate");
94         mContext = getApplicationContext();
95         mQnsComponents = new QnsComponents(mContext);
96         mHandlerThread = new HandlerThread(LOG_TAG);
97         mHandlerThread.start();
98     }
99 
100     @Override
onDestroy()101     public void onDestroy() {
102         log("onDestroy");
103         for (NetworkAvailabilityProviderImpl provider : mProviderMap.values()) {
104             provider.close();
105         }
106         for (HandlerThread ht : mHandlerThreadMap.values()) {
107             ht.quitSafely();
108         }
109         mHandlerThreadMap.clear();
110         mProviderMap.clear();
111         mHandlerThread.quitSafely();
112         super.onDestroy();
113     }
114 
log(String s)115     protected void log(String s) {
116         if (DBG) Log.d(LOG_TAG, s);
117     }
118 
119     static class QualifiedNetworksInfo {
120         int mNetCapability;
121         List<Integer> mAccessNetworkTypes;
122 
QualifiedNetworksInfo(int netCapability, List<Integer> accessNetworkTypes)123         QualifiedNetworksInfo(int netCapability, List<Integer> accessNetworkTypes) {
124             mNetCapability = netCapability;
125             mAccessNetworkTypes = accessNetworkTypes;
126         }
127 
getNetCapability()128         int getNetCapability() {
129             return mNetCapability;
130         }
131 
setNetCapability(int netCapability)132         void setNetCapability(int netCapability) {
133             mNetCapability = netCapability;
134         }
135 
getAccessNetworkTypes()136         List<Integer> getAccessNetworkTypes() {
137             return mAccessNetworkTypes;
138         }
139 
setAccessNetworkTypes(List<Integer> accessNetworkTypes)140         void setAccessNetworkTypes(List<Integer> accessNetworkTypes) {
141             mAccessNetworkTypes = accessNetworkTypes;
142         }
143     }
144 
145     /**
146      * The network availability provider implementation class. The qualified network service must
147      * extend this class to report the available networks for data connection setup. Note that each
148      * instance of network availability provider is associated with slot.
149      */
150     public class NetworkAvailabilityProviderImpl extends NetworkAvailabilityProvider {
151         private final String mLogTag;
152         private final int mSlotIndex;
153         @VisibleForTesting Handler mHandler;
154         @VisibleForTesting Handler mConfigHandler;
155         private boolean mIsQnsConfigChangeRegistered = false;
156 
157         protected QnsCarrierConfigManager mConfigManager;
158         protected HashMap<Integer, AccessNetworkEvaluator> mEvaluators = new HashMap<>();
159         private boolean mIsClosed;
160 
161         /**
162          * Constructor
163          *
164          * @param slotIndex SIM slot index the network availability provider associated with.
165          */
NetworkAvailabilityProviderImpl(int slotIndex)166         public NetworkAvailabilityProviderImpl(int slotIndex) {
167             super(slotIndex);
168             mLogTag = NetworkAvailabilityProviderImpl.class.getSimpleName() + "_" + slotIndex;
169 
170             mIsClosed = false;
171             mSlotIndex = slotIndex;
172             mConfigHandler = new NapHandler(mHandlerThreadMap.get(mSlotIndex).getLooper());
173             mConfigHandler.post(this::initNetworkAvailabilityProvider);
174             mHandler = new NapHandler(mHandlerThread.getLooper());
175         }
176 
177         private class NapHandler extends Handler {
NapHandler(Looper looper)178             NapHandler(Looper looper) {
179                 super(looper);
180             }
181 
182             @Override
handleMessage(Message msg)183             public void handleMessage(Message msg) {
184                 super.handleMessage(msg);
185                 switch (msg.what) {
186                     case QNS_CONFIGURATION_LOADED:
187                         onConfigurationLoaded();
188                         break;
189                     case QNS_CONFIGURATION_CHANGED:
190                         log("Qns Configuration changed received");
191                         onConfigurationChanged();
192                         break;
193                     case QUALIFIED_NETWORKS_CHANGED:
194                         QnsAsyncResult ar = (QnsAsyncResult) msg.obj;
195                         onQualifiedNetworksChanged((QualifiedNetworksInfo) ar.mResult);
196                         break;
197                     default:
198                         log("got event " + msg.what + " never reached here.");
199                         break;
200                 }
201             }
202         }
203 
initNetworkAvailabilityProvider()204         private void initNetworkAvailabilityProvider() {
205             mQnsComponents.createQnsComponents(mSlotIndex);
206             mConfigManager = mQnsComponents.getQnsCarrierConfigManager(mSlotIndex);
207             mConfigManager.registerForConfigurationLoaded(mConfigHandler, QNS_CONFIGURATION_LOADED);
208         }
209 
onConfigurationLoaded()210         protected void onConfigurationLoaded() {
211             log("onConfigurationLoaded");
212             // Register for Upgradable Config items load case
213             if (!mIsQnsConfigChangeRegistered) {
214                 mConfigManager.registerForConfigurationChanged(
215                         mConfigHandler, QNS_CONFIGURATION_CHANGED);
216                 mIsQnsConfigChangeRegistered = true;
217             }
218 
219             HashMap<Integer, AccessNetworkEvaluator> evaluators = new HashMap<>();
220             List<Integer> netCapabilities = mConfigManager.getQnsSupportedNetCapabilities();
221 
222             for (int netCapability : netCapabilities) {
223                 int transportType = mConfigManager.getQnsSupportedTransportType(netCapability);
224                 if (transportType < 0
225                         || transportType == QnsConstants.TRANSPORT_TYPE_ALLOWED_WWAN) {
226                     continue;
227                 }
228                 if (mEvaluators.get(netCapability) != null) {
229                     AccessNetworkEvaluator evaluator = mEvaluators.remove(netCapability);
230                     evaluators.put(netCapability, evaluator);
231                     // reuse evaluator
232                     evaluator.rebuild();
233                 } else {
234                     AccessNetworkEvaluator evaluator =
235                             new AccessNetworkEvaluator(mQnsComponents, netCapability, mSlotIndex);
236                     evaluator.registerForQualifiedNetworksChanged(
237                             mHandler, QUALIFIED_NETWORKS_CHANGED);
238                     evaluators.put(netCapability, evaluator);
239                 }
240             }
241             for (Integer capability : mEvaluators.keySet()) {
242                 AccessNetworkEvaluator evaluator = mEvaluators.get(capability);
243                 evaluator.unregisterForQualifiedNetworksChanged(mHandler);
244                 evaluator.close();
245             }
246             mEvaluators.clear();
247             mEvaluators = evaluators;
248         }
249 
onConfigurationChanged()250         protected void onConfigurationChanged() {}
251 
onQualifiedNetworksChanged(QualifiedNetworksInfo info)252         private void onQualifiedNetworksChanged(QualifiedNetworksInfo info) {
253             log(
254                     "Calling updateQualifiedNetworkTypes for mNetCapability["
255                             + QnsUtils.getNameOfNetCapability(info.getNetCapability())
256                             + "], preferred networks "
257                             + QnsUtils.getStringAccessNetworkTypes(info.getAccessNetworkTypes()));
258 
259             int apnType = QnsUtils.getApnTypeFromNetCapability(info.getNetCapability());
260             updateQualifiedNetworkTypes(apnType, info.getAccessNetworkTypes());
261         }
262 
263         @Override
reportThrottleStatusChanged(@onNull List<ThrottleStatus> statuses)264         public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
265             log("reportThrottleStatusChanged: statuses size=" + statuses.size());
266             for (ThrottleStatus ts : statuses) {
267                 int netCapability;
268                 try {
269                     netCapability = QnsUtils.getNetCapabilityFromApnType(ts.getApnType());
270                 } catch (IllegalArgumentException e) {
271                     continue;
272                 }
273                 log("ThrottleStatus:" + ts + ", netCapability" + netCapability);
274                 if (ts.getSlotIndex() != getSlotIndex()) {
275                     continue;
276                 }
277                 AccessNetworkEvaluator evaluator = mEvaluators.get(netCapability);
278                 if (evaluator == null) {
279                     continue;
280                 }
281                 boolean isThrottle = ts.getThrottleType() == THROTTLE_TYPE_ELAPSED_TIME;
282                 evaluator.updateThrottleStatus(
283                         isThrottle, ts.getThrottleExpiryTimeMillis(), ts.getTransportType());
284             }
285         }
286 
287         @Override
reportEmergencyDataNetworkPreferredTransportChanged( @ccessNetworkConstants.TransportType int transportType)288         public void reportEmergencyDataNetworkPreferredTransportChanged(
289                 @AccessNetworkConstants.TransportType int transportType) {
290             log("reportEmergencyDataNetworkPreferredTransportChanged: "
291                     + QnsConstants.transportTypeToString(transportType));
292             AccessNetworkEvaluator evaluator =
293                     mEvaluators.get(NetworkCapabilities.NET_CAPABILITY_EIMS);
294             if (evaluator != null) {
295                 evaluator.onEmergencyPreferredTransportTypeChanged(transportType);
296             } else {
297                 log("There is no Emergency ANE");
298             }
299         }
300 
301         @Override
close()302         public synchronized void close() {
303             mConfigHandler.post(this::onClose);
304         }
305 
onClose()306         private synchronized void onClose() {
307             if (!mIsClosed) {
308                 mIsClosed = true;
309                 log("closing NetworkAvailabilityProviderImpl");
310                 mConfigManager.unregisterForConfigurationLoaded(mConfigHandler);
311                 mConfigManager.unregisterForConfigurationChanged(mConfigHandler);
312                 mIsQnsConfigChangeRegistered = false;
313                 for (Integer netCapability : mEvaluators.keySet()) {
314                     AccessNetworkEvaluator evaluator = mEvaluators.get(netCapability);
315                     evaluator.unregisterForQualifiedNetworksChanged(mHandler);
316                     evaluator.close();
317                 }
318                 mQnsComponents.closeComponents(mSlotIndex);
319                 mEvaluators.clear();
320             }
321         }
322 
log(String s)323         protected void log(String s) {
324             if (DBG) Log.d(mLogTag, s);
325         }
326 
327         /**
328          * Dumps the state of {@link QualityMonitor}
329          *
330          * @param pw {@link PrintWriter} to write the state of the object.
331          * @param prefix String to append at start of dumped log.
332          */
dump(PrintWriter pw, String prefix)333         void dump(PrintWriter pw, String prefix) {
334             pw.println(prefix + "------------------------------");
335             pw.println(prefix + "NetworkAvailabilityProviderImpl[" + mSlotIndex + "]:");
336             for (Map.Entry<Integer, AccessNetworkEvaluator> aneMap : mEvaluators.entrySet()) {
337                 AccessNetworkEvaluator ane = aneMap.getValue();
338                 ane.dump(pw, prefix + "  ");
339             }
340             QnsTelephonyListener tl = mQnsComponents.getQnsTelephonyListener(mSlotIndex);
341             if (tl != null) {
342                 tl.dump(pw, prefix + "  ");
343             }
344             CellularQualityMonitor cQM = mQnsComponents.getCellularQualityMonitor(mSlotIndex);
345             if (cQM != null) {
346                 cQM.dump(pw, prefix + "  ");
347             }
348         }
349     }
350 
351     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)352     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
353         super.dump(fd, pw, args);
354         pw.println("QualifiedNetworksServiceImpl:");
355         pw.println("==============================");
356         for (Map.Entry<Integer, NetworkAvailabilityProviderImpl> providerMap :
357                 mProviderMap.entrySet()) {
358             NetworkAvailabilityProviderImpl provider = providerMap.getValue();
359             provider.dump(pw, "  ");
360         }
361         mQnsComponents.dump(pw);
362         pw.println("==============================");
363     }
364 }
365