1 /*
2  * Copyright 2018 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.telephony.data;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.FlaggedApi;
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.app.Service;
24 import android.content.Intent;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 import android.os.IBinder;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.RemoteException;
31 import android.telephony.AccessNetworkConstants;
32 import android.telephony.AccessNetworkConstants.AccessNetworkType;
33 import android.telephony.Annotation.ApnType;
34 import android.telephony.Annotation.NetCapability;
35 import android.telephony.PreciseDataConnectionState;
36 import android.telephony.TelephonyManager;
37 import android.util.Log;
38 import android.util.SparseArray;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.telephony.IIntegerConsumer;
42 import com.android.internal.telephony.flags.FeatureFlags;
43 import com.android.internal.telephony.flags.FeatureFlagsImpl;
44 import com.android.internal.telephony.flags.Flags;
45 import com.android.internal.util.FunctionalUtils;
46 import com.android.telephony.Rlog;
47 
48 import java.util.List;
49 import java.util.Objects;
50 import java.util.concurrent.Executor;
51 import java.util.function.Consumer;
52 
53 /**
54  * Base class of the qualified networks service, which is a vendor service providing up-to-date
55  * qualified network information to the frameworks for data handover control. A qualified network
56  * is defined as an access network that is ready for bringing up data connection for given APN
57  * types.
58  *
59  * Services that extend QualifiedNetworksService must register the service in their AndroidManifest
60  * to be detected by the framework. They must be protected by the permission
61  * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The qualified networks service definition in
62  * the manifest must follow the following format:
63  * ...
64  * <service android:name=".xxxQualifiedNetworksService"
65  *     android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" >
66  *     <intent-filter>
67  *         <action android:name="android.telephony.data.QualifiedNetworksService" />
68  *     </intent-filter>
69  * </service>
70  * @hide
71  */
72 @SystemApi
73 public abstract class QualifiedNetworksService extends Service {
74     private static final String TAG = QualifiedNetworksService.class.getSimpleName();
75 
76     public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE =
77             "android.telephony.data.QualifiedNetworksService";
78 
79     private static final int QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER               = 1;
80     private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER               = 2;
81     private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS          = 3;
82     private static final int QNS_UPDATE_QUALIFIED_NETWORKS                          = 4;
83     private static final int QNS_APN_THROTTLE_STATUS_CHANGED                        = 5;
84     private static final int QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED = 6;
85     private static final int QNS_REQUEST_NETWORK_VALIDATION                         = 7;
86     private static final int QNS_RECONNECT_QUALIFIED_NETWORK                        = 8;
87 
88     /** Feature flags */
89     private static final FeatureFlags sFeatureFlag = new FeatureFlagsImpl();
90 
91     private final HandlerThread mHandlerThread;
92 
93     private final QualifiedNetworksServiceHandler mHandler;
94 
95     private final SparseArray<NetworkAvailabilityProvider> mProviders = new SparseArray<>();
96 
97     /** @hide */
98     @VisibleForTesting
99     public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();
100 
101     /**
102      * The abstract class of the network availability provider implementation. The vendor qualified
103      * network service must extend this class to report the available networks for data
104      * connection setup. Note that each instance of network availability provider is associated with
105      * one physical SIM slot.
106      */
107     public abstract class NetworkAvailabilityProvider implements AutoCloseable {
108         private final int mSlotIndex;
109 
110         private IQualifiedNetworksServiceCallback mCallback;
111 
112         /**
113          * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array
114          * of available networks.
115          */
116         private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>();
117 
118         /**
119          * Constructor
120          * @param slotIndex SIM slot index the network availability provider associated with.
121          */
NetworkAvailabilityProvider(int slotIndex)122         public NetworkAvailabilityProvider(int slotIndex) {
123             mSlotIndex = slotIndex;
124         }
125 
126         /**
127          * @return SIM slot index the network availability provider associated with.
128          */
getSlotIndex()129         public final int getSlotIndex() {
130             return mSlotIndex;
131         }
132 
registerForQualifiedNetworkTypesChanged( IQualifiedNetworksServiceCallback callback)133         private void registerForQualifiedNetworkTypesChanged(
134                 IQualifiedNetworksServiceCallback callback) {
135             mCallback = callback;
136 
137             // Force sending the qualified networks upon registered.
138             if (mCallback != null) {
139                 for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) {
140                     try {
141                         mCallback.onQualifiedNetworkTypesChanged(
142                                 mQualifiedNetworkTypesList.keyAt(i),
143                                 mQualifiedNetworkTypesList.valueAt(i));
144                     } catch (RemoteException e) {
145                         loge("Failed to call onQualifiedNetworksChanged. " + e);
146                     }
147                 }
148             }
149         }
150 
151         /**
152          * Update the suggested qualified networks list. Network availability provider must invoke
153          * this method whenever the suggested qualified networks changes. If this method is never
154          * invoked for certain APN types, then frameworks uses its own logic to determine the
155          * transport to setup the data network.
156          *
157          * For example, QNS can suggest frameworks setting up IMS data network on IWLAN by
158          * specifying {@link ApnSetting#TYPE_IMS} with a list containing
159          * {@link AccessNetworkType#IWLAN}.
160          *
161          * If QNS considers multiple access networks qualified for certain APN type, it can
162          * suggest frameworks by specifying the APN type with multiple access networks in the list,
163          * for example {{@link AccessNetworkType#EUTRAN}, {@link AccessNetworkType#IWLAN}}.
164          * Frameworks will then first attempt to setup data on LTE network, and If the device moves
165          * from LTE to UMTS, then frameworks will perform handover the data network to the second
166          * preferred access network if available.
167          *
168          * If the {@code qualifiedNetworkTypes} list is empty, it means QNS has no suggestion to the
169          * frameworks, and for that APN type frameworks will route the corresponding network
170          * requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
171          *
172          * @param apnTypes APN type(s) of the qualified networks. This must be a bitmask combination
173          * of {@link ApnType}. The same qualified networks will be applicable to all APN types
174          * specified here.
175          * @param qualifiedNetworkTypes List of access network types which are qualified for data
176          * connection setup for {@code apnTypes} in the preferred order. Empty list means QNS has no
177          * suggestion to the frameworks, and for that APN type frameworks will route the
178          * corresponding network requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
179          *
180          * If one of the element is invalid, for example, {@link AccessNetworkType#UNKNOWN}, then
181          * this operation becomes a no-op.
182          */
updateQualifiedNetworkTypes( @pnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes)183         public final void updateQualifiedNetworkTypes(
184                 @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
185             int[] qualifiedNetworkTypesArray =
186                     qualifiedNetworkTypes.stream().mapToInt(i->i).toArray();
187             mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes,
188                     qualifiedNetworkTypesArray).sendToTarget();
189         }
190 
191         /**
192          * Request to make a clean initial connection instead of handover to a transport type mapped
193          * to the {@code qualifiedNetworkType} for the {@code apnTypes}. This will update the
194          * preferred network type like {@link #updateQualifiedNetworkTypes(int, List)}, however if
195          * the data network for the {@code apnTypes} is not in the state {@link TelephonyManager
196          * #DATA_CONNECTED} or it's already connected on the transport type mapped to the
197          * qualified network type, forced reconnection will be ignored.
198          *
199          * <p>This will tear down current data network even though target transport type mapped to
200          * the {@code qualifiedNetworkType} is not available, and the data network will be connected
201          * to the transport type when it becomes available.
202          *
203          * <p>This is one shot request and does not mean further handover is not allowed to the
204          * qualified network type for this APN type.
205          *
206          * @param apnTypes APN type(s) of the qualified networks. This must be a bitmask combination
207          * of {@link ApnType}. The same qualified networks will be applicable to all APN types
208          * specified here.
209          * @param qualifiedNetworkType Access network types which are qualified for data connection
210          * setup for {@link ApnType}. Empty list means QNS has no suggestion to the frameworks, and
211          * for that APN type frameworks will route the corresponding network requests to
212          * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
213          *
214          * <p> If one of the element is invalid, for example, {@link AccessNetworkType#UNKNOWN},
215          * then this operation becomes a no-op.
216          *
217          * @hide
218          */
reconnectQualifiedNetworkType(@pnType int apnTypes, @AccessNetworkConstants.RadioAccessNetworkType int qualifiedNetworkType)219         public final void reconnectQualifiedNetworkType(@ApnType int apnTypes,
220                 @AccessNetworkConstants.RadioAccessNetworkType int qualifiedNetworkType) {
221             mHandler.obtainMessage(QNS_RECONNECT_QUALIFIED_NETWORK, mSlotIndex, apnTypes,
222                     new Integer(qualifiedNetworkType)).sendToTarget();
223         }
224 
onUpdateQualifiedNetworkTypes( @pnType int apnTypes, int[] qualifiedNetworkTypes)225         private void onUpdateQualifiedNetworkTypes(
226                 @ApnType int apnTypes, int[] qualifiedNetworkTypes) {
227             mQualifiedNetworkTypesList.put(apnTypes, qualifiedNetworkTypes);
228             if (mCallback != null) {
229                 try {
230                     mCallback.onQualifiedNetworkTypesChanged(apnTypes, qualifiedNetworkTypes);
231                 } catch (RemoteException e) {
232                     loge("Failed to call onQualifiedNetworksChanged. " + e);
233                 }
234             }
235         }
236 
onReconnectQualifiedNetworkType(@pnType int apnTypes, @AccessNetworkConstants.RadioAccessNetworkType int qualifiedNetworkType)237         private void onReconnectQualifiedNetworkType(@ApnType int apnTypes,
238                 @AccessNetworkConstants.RadioAccessNetworkType int qualifiedNetworkType) {
239             if (mCallback != null) {
240                 try {
241                     mCallback.onReconnectQualifiedNetworkType(apnTypes, qualifiedNetworkType);
242                 } catch (RemoteException e) {
243                     loge("Failed to call onReconnectQualifiedNetworkType. " + e);
244                 }
245             }
246         }
247 
248         /**
249          * The framework calls this method when the throttle status of an APN changes.
250          *
251          * This method is meant to be overridden.
252          *
253          * @param statuses the statuses that have changed
254          */
reportThrottleStatusChanged(@onNull List<ThrottleStatus> statuses)255         public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
256             Log.d(TAG, "reportThrottleStatusChanged: statuses size=" + statuses.size());
257         }
258 
259         /**
260          * The framework calls this method when the preferred transport type used to set up
261          * emergency data network is changed.
262          *
263          * This method is meant to be overridden.
264          *
265          * @param transportType transport type changed to be preferred
266          */
reportEmergencyDataNetworkPreferredTransportChanged( @ccessNetworkConstants.TransportType int transportType)267         public void reportEmergencyDataNetworkPreferredTransportChanged(
268                 @AccessNetworkConstants.TransportType int transportType) {
269             Log.d(TAG, "reportEmergencyDataNetworkPreferredTransportChanged: "
270                     + AccessNetworkConstants.transportTypeToString(transportType));
271         }
272 
273         /**
274          * Request network validation to the connected data network for given a network capability.
275          *
276          * <p>This network validation can only be performed when a data network is in connected
277          * state, and will not be triggered if the data network does not support network validation
278          * feature or network validation is not in connected state.
279          *
280          * <p>See {@link DataServiceCallback.ResultCode} for the type of response that indicates
281          * whether the request was successfully submitted or had an error.
282          *
283          * <p>If network validation is requested, monitor network validation status in {@link
284          * PreciseDataConnectionState#getNetworkValidationStatus()}.
285          *
286          * @param networkCapability A network capability. (Note that only APN-type capabilities are
287          *     supported.
288          * @param executor executor The callback executor that responds whether the request has been
289          *     successfully submitted or not.
290          * @param resultCodeCallback A callback to determine whether the request was successfully
291          *     submitted or not.
292          */
293         @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION)
requestNetworkValidation( @etCapability int networkCapability, @NonNull @CallbackExecutor Executor executor, @NonNull @DataServiceCallback.ResultCode Consumer<Integer> resultCodeCallback)294         public void requestNetworkValidation(
295                 @NetCapability int networkCapability,
296                 @NonNull @CallbackExecutor Executor executor,
297                 @NonNull @DataServiceCallback.ResultCode Consumer<Integer> resultCodeCallback) {
298             Objects.requireNonNull(executor, "executor cannot be null");
299             Objects.requireNonNull(resultCodeCallback, "resultCodeCallback cannot be null");
300 
301             if (!sFeatureFlag.networkValidation()) {
302                 loge("networkValidation feature is disabled");
303                 executor.execute(
304                         () ->
305                                 resultCodeCallback.accept(
306                                         DataServiceCallback.RESULT_ERROR_UNSUPPORTED));
307                 return;
308             }
309 
310             IIntegerConsumer callback = new IIntegerConsumer.Stub() {
311                 @Override
312                 public void accept(int result) {
313                     executor.execute(() -> resultCodeCallback.accept(result));
314                 }
315             };
316 
317             // Move to the internal handler and process it.
318             mHandler.obtainMessage(
319                             QNS_REQUEST_NETWORK_VALIDATION,
320                             mSlotIndex,
321                             0,
322                             new NetworkValidationRequestData(networkCapability, callback))
323                     .sendToTarget();
324         }
325 
326         /** Process a network validation request on the internal handler. */
onRequestNetworkValidation(NetworkValidationRequestData data)327         private void onRequestNetworkValidation(NetworkValidationRequestData data) {
328             try {
329                 log("onRequestNetworkValidation");
330                 // Callback to request a network validation.
331                 mCallback.onNetworkValidationRequested(data.mNetworkCapability, data.mCallback);
332             } catch (RemoteException | NullPointerException e) {
333                 loge("Failed to call onRequestNetworkValidation. " + e);
334                 FunctionalUtils.ignoreRemoteException(data.mCallback::accept)
335                         .accept(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
336             }
337         }
338 
339         /**
340          * Called when the qualified networks provider is removed. The extended class should
341          * implement this method to perform cleanup works.
342          */
343         @Override
close()344         public abstract void close();
345     }
346 
347     private class QualifiedNetworksServiceHandler extends Handler {
QualifiedNetworksServiceHandler(Looper looper)348         QualifiedNetworksServiceHandler(Looper looper) {
349             super(looper);
350         }
351 
352         @Override
handleMessage(Message message)353         public void handleMessage(Message message) {
354             IQualifiedNetworksServiceCallback callback;
355             final int slotIndex = message.arg1;
356             NetworkAvailabilityProvider provider = mProviders.get(slotIndex);
357 
358             switch (message.what) {
359                 case QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER:
360                     if (mProviders.get(slotIndex) != null) {
361                         loge("Network availability provider for slot " + slotIndex
362                                 + " already existed.");
363                         return;
364                     }
365 
366                     provider = onCreateNetworkAvailabilityProvider(slotIndex);
367                     if (provider != null) {
368                         mProviders.put(slotIndex, provider);
369 
370                         callback = (IQualifiedNetworksServiceCallback) message.obj;
371                         provider.registerForQualifiedNetworkTypesChanged(callback);
372                     } else {
373                         loge("Failed to create network availability provider. slot index = "
374                                 + slotIndex);
375                     }
376                     break;
377                 case QNS_APN_THROTTLE_STATUS_CHANGED:
378                     if (provider != null) {
379                         List<ThrottleStatus> statuses = (List<ThrottleStatus>) message.obj;
380                         provider.reportThrottleStatusChanged(statuses);
381                     }
382                     break;
383 
384                 case QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED:
385                     if (provider != null) {
386                         int transportType = (int) message.arg2;
387                         provider.reportEmergencyDataNetworkPreferredTransportChanged(transportType);
388                     }
389                     break;
390 
391                 case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
392                     if (provider != null) {
393                         provider.close();
394                         mProviders.remove(slotIndex);
395                     }
396                     break;
397 
398                 case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS:
399                     for (int i = 0; i < mProviders.size(); i++) {
400                         provider = mProviders.get(i);
401                         if (provider != null) {
402                             provider.close();
403                         }
404                     }
405                     mProviders.clear();
406                     break;
407 
408                 case QNS_UPDATE_QUALIFIED_NETWORKS:
409                     if (provider == null) break;
410                     provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
411                     break;
412 
413                 case QNS_REQUEST_NETWORK_VALIDATION:
414                     if (provider == null) break;
415                     provider.onRequestNetworkValidation((NetworkValidationRequestData) message.obj);
416                     break;
417 
418                 case QNS_RECONNECT_QUALIFIED_NETWORK:
419                     if (provider == null) break;
420                     provider.onReconnectQualifiedNetworkType(message.arg2, (Integer) message.obj);
421                     break;
422             }
423         }
424     }
425 
426     /**
427      * Default constructor.
428      */
QualifiedNetworksService()429     public QualifiedNetworksService() {
430         mHandlerThread = new HandlerThread(TAG);
431         mHandlerThread.start();
432 
433         mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper());
434         log("Qualified networks service created");
435     }
436 
437     /**
438      * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
439      * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
440      * instances. The system will call this method after binding the qualified networks service for
441      * each active SIM slot index.
442      *
443      * @param slotIndex SIM slot index the qualified networks service associated with.
444      * @return Qualified networks service instance
445      */
446     @NonNull
onCreateNetworkAvailabilityProvider(int slotIndex)447     public abstract NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex);
448 
449     /** @hide */
450     @Override
onBind(Intent intent)451     public IBinder onBind(Intent intent) {
452         if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) {
453             loge("Unexpected intent " + intent);
454             return null;
455         }
456         return mBinder;
457     }
458 
459     /** @hide */
460     @Override
onUnbind(Intent intent)461     public boolean onUnbind(Intent intent) {
462         mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS).sendToTarget();
463         return false;
464     }
465 
466     /** @hide */
467     @Override
onDestroy()468     public void onDestroy() {
469         mHandlerThread.quit();
470     }
471 
472     /**
473      * A wrapper around IQualifiedNetworksService that forwards calls to implementations of
474      * {@link QualifiedNetworksService}.
475      */
476     private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
477         @Override
createNetworkAvailabilityProvider(int slotIndex, IQualifiedNetworksServiceCallback callback)478         public void createNetworkAvailabilityProvider(int slotIndex,
479                                                       IQualifiedNetworksServiceCallback callback) {
480             mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0,
481                     callback).sendToTarget();
482         }
483 
484         @Override
removeNetworkAvailabilityProvider(int slotIndex)485         public void removeNetworkAvailabilityProvider(int slotIndex) {
486             mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
487                     .sendToTarget();
488         }
489 
490         @Override
reportThrottleStatusChanged(int slotIndex, List<ThrottleStatus> statuses)491         public void reportThrottleStatusChanged(int slotIndex,
492                 List<ThrottleStatus> statuses) {
493             mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
494                     .sendToTarget();
495         }
496 
497         @Override
reportEmergencyDataNetworkPreferredTransportChanged(int slotIndex, @AccessNetworkConstants.TransportType int transportType)498         public void reportEmergencyDataNetworkPreferredTransportChanged(int slotIndex,
499                 @AccessNetworkConstants.TransportType int transportType) {
500             mHandler.obtainMessage(
501                     QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED,
502                             slotIndex, transportType).sendToTarget();
503         }
504     }
505 
506     private static final class NetworkValidationRequestData {
507         final @NetCapability int mNetworkCapability;
508         final IIntegerConsumer mCallback;
509 
NetworkValidationRequestData(@etCapability int networkCapability, @NonNull IIntegerConsumer callback)510         private NetworkValidationRequestData(@NetCapability int networkCapability,
511                 @NonNull IIntegerConsumer callback) {
512             mNetworkCapability = networkCapability;
513             mCallback = callback;
514         }
515     }
516 
log(String s)517     private void log(String s) {
518         Rlog.d(TAG, s);
519     }
520 
loge(String s)521     private void loge(String s) {
522         Rlog.e(TAG, s);
523     }
524 }
525