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.NonNull;
20 import android.annotation.SystemApi;
21 import android.app.Service;
22 import android.content.Intent;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.IBinder;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.telephony.AccessNetworkConstants;
30 import android.telephony.AccessNetworkConstants.AccessNetworkType;
31 import android.telephony.Annotation.ApnType;
32 import android.util.Log;
33 import android.util.SparseArray;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.telephony.Rlog;
37 
38 import java.util.List;
39 
40 /**
41  * Base class of the qualified networks service, which is a vendor service providing up-to-date
42  * qualified network information to the frameworks for data handover control. A qualified network
43  * is defined as an access network that is ready for bringing up data connection for given APN
44  * types.
45  *
46  * Services that extend QualifiedNetworksService must register the service in their AndroidManifest
47  * to be detected by the framework. They must be protected by the permission
48  * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The qualified networks service definition in
49  * the manifest must follow the following format:
50  * ...
51  * <service android:name=".xxxQualifiedNetworksService"
52  *     android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" >
53  *     <intent-filter>
54  *         <action android:name="android.telephony.data.QualifiedNetworksService" />
55  *     </intent-filter>
56  * </service>
57  * @hide
58  */
59 @SystemApi
60 public abstract class QualifiedNetworksService extends Service {
61     private static final String TAG = QualifiedNetworksService.class.getSimpleName();
62 
63     public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE =
64             "android.telephony.data.QualifiedNetworksService";
65 
66     private static final int QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER               = 1;
67     private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER               = 2;
68     private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS          = 3;
69     private static final int QNS_UPDATE_QUALIFIED_NETWORKS                          = 4;
70     private static final int QNS_APN_THROTTLE_STATUS_CHANGED                        = 5;
71     private static final int QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED = 6;
72 
73     private final HandlerThread mHandlerThread;
74 
75     private final QualifiedNetworksServiceHandler mHandler;
76 
77     private final SparseArray<NetworkAvailabilityProvider> mProviders = new SparseArray<>();
78 
79     /** @hide */
80     @VisibleForTesting
81     public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();
82 
83     /**
84      * The abstract class of the network availability provider implementation. The vendor qualified
85      * network service must extend this class to report the available networks for data
86      * connection setup. Note that each instance of network availability provider is associated with
87      * one physical SIM slot.
88      */
89     public abstract class NetworkAvailabilityProvider implements AutoCloseable {
90         private final int mSlotIndex;
91 
92         private IQualifiedNetworksServiceCallback mCallback;
93 
94         /**
95          * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array
96          * of available networks.
97          */
98         private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>();
99 
100         /**
101          * Constructor
102          * @param slotIndex SIM slot index the network availability provider associated with.
103          */
NetworkAvailabilityProvider(int slotIndex)104         public NetworkAvailabilityProvider(int slotIndex) {
105             mSlotIndex = slotIndex;
106         }
107 
108         /**
109          * @return SIM slot index the network availability provider associated with.
110          */
getSlotIndex()111         public final int getSlotIndex() {
112             return mSlotIndex;
113         }
114 
registerForQualifiedNetworkTypesChanged( IQualifiedNetworksServiceCallback callback)115         private void registerForQualifiedNetworkTypesChanged(
116                 IQualifiedNetworksServiceCallback callback) {
117             mCallback = callback;
118 
119             // Force sending the qualified networks upon registered.
120             if (mCallback != null) {
121                 for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) {
122                     try {
123                         mCallback.onQualifiedNetworkTypesChanged(
124                                 mQualifiedNetworkTypesList.keyAt(i),
125                                 mQualifiedNetworkTypesList.valueAt(i));
126                     } catch (RemoteException e) {
127                         loge("Failed to call onQualifiedNetworksChanged. " + e);
128                     }
129                 }
130             }
131         }
132 
133         /**
134          * Update the suggested qualified networks list. Network availability provider must invoke
135          * this method whenever the suggested qualified networks changes. If this method is never
136          * invoked for certain APN types, then frameworks uses its own logic to determine the
137          * transport to setup the data network.
138          *
139          * For example, QNS can suggest frameworks setting up IMS data network on IWLAN by
140          * specifying {@link ApnSetting#TYPE_IMS} with a list containing
141          * {@link AccessNetworkType#IWLAN}.
142          *
143          * If QNS considers multiple access networks qualified for certain APN type, it can
144          * suggest frameworks by specifying the APN type with multiple access networks in the list,
145          * for example {{@link AccessNetworkType#EUTRAN}, {@link AccessNetworkType#IWLAN}}.
146          * Frameworks will then first attempt to setup data on LTE network, and If the device moves
147          * from LTE to UMTS, then frameworks will perform handover the data network to the second
148          * preferred access network if available.
149          *
150          * If the {@code qualifiedNetworkTypes} list is empty, it means QNS has no suggestion to the
151          * frameworks, and for that APN type frameworks will route the corresponding network
152          * requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
153          *
154          * @param apnTypes APN type(s) of the qualified networks. This must be a bitmask combination
155          * of {@link ApnType}. The same qualified networks will be applicable to all APN types
156          * specified here.
157          * @param qualifiedNetworkTypes List of access network types which are qualified for data
158          * connection setup for {@code apnTypes} in the preferred order. Empty list means QNS has no
159          * suggestion to the frameworks, and for that APN type frameworks will route the
160          * corresponding network requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
161          *
162          * If one of the element is invalid, for example, {@link AccessNetworkType#UNKNOWN}, then
163          * this operation becomes a no-op.
164          */
updateQualifiedNetworkTypes( @pnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes)165         public final void updateQualifiedNetworkTypes(
166                 @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
167             int[] qualifiedNetworkTypesArray =
168                     qualifiedNetworkTypes.stream().mapToInt(i->i).toArray();
169             mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes,
170                     qualifiedNetworkTypesArray).sendToTarget();
171         }
172 
onUpdateQualifiedNetworkTypes(@pnType int apnTypes, int[] qualifiedNetworkTypes)173         private void onUpdateQualifiedNetworkTypes(@ApnType int apnTypes,
174                                                    int[] qualifiedNetworkTypes) {
175             mQualifiedNetworkTypesList.put(apnTypes, qualifiedNetworkTypes);
176             if (mCallback != null) {
177                 try {
178                     mCallback.onQualifiedNetworkTypesChanged(apnTypes, qualifiedNetworkTypes);
179                 } catch (RemoteException e) {
180                     loge("Failed to call onQualifiedNetworksChanged. " + e);
181                 }
182             }
183         }
184 
185         /**
186          * The framework calls this method when the throttle status of an APN changes.
187          *
188          * This method is meant to be overridden.
189          *
190          * @param statuses the statuses that have changed
191          */
reportThrottleStatusChanged(@onNull List<ThrottleStatus> statuses)192         public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
193             Log.d(TAG, "reportThrottleStatusChanged: statuses size=" + statuses.size());
194         }
195 
196         /**
197          * The framework calls this method when the preferred transport type used to set up
198          * emergency data network is changed.
199          *
200          * This method is meant to be overridden.
201          *
202          * @param transportType transport type changed to be preferred
203          */
reportEmergencyDataNetworkPreferredTransportChanged( @ccessNetworkConstants.TransportType int transportType)204         public void reportEmergencyDataNetworkPreferredTransportChanged(
205                 @AccessNetworkConstants.TransportType int transportType) {
206             Log.d(TAG, "reportEmergencyDataNetworkPreferredTransportChanged: "
207                     + AccessNetworkConstants.transportTypeToString(transportType));
208         }
209 
210         /**
211          * Called when the qualified networks provider is removed. The extended class should
212          * implement this method to perform cleanup works.
213          */
214         @Override
close()215         public abstract void close();
216     }
217 
218     private class QualifiedNetworksServiceHandler extends Handler {
QualifiedNetworksServiceHandler(Looper looper)219         QualifiedNetworksServiceHandler(Looper looper) {
220             super(looper);
221         }
222 
223         @Override
handleMessage(Message message)224         public void handleMessage(Message message) {
225             IQualifiedNetworksServiceCallback callback;
226             final int slotIndex = message.arg1;
227             NetworkAvailabilityProvider provider = mProviders.get(slotIndex);
228 
229             switch (message.what) {
230                 case QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER:
231                     if (mProviders.get(slotIndex) != null) {
232                         loge("Network availability provider for slot " + slotIndex
233                                 + " already existed.");
234                         return;
235                     }
236 
237                     provider = onCreateNetworkAvailabilityProvider(slotIndex);
238                     if (provider != null) {
239                         mProviders.put(slotIndex, provider);
240 
241                         callback = (IQualifiedNetworksServiceCallback) message.obj;
242                         provider.registerForQualifiedNetworkTypesChanged(callback);
243                     } else {
244                         loge("Failed to create network availability provider. slot index = "
245                                 + slotIndex);
246                     }
247                     break;
248                 case QNS_APN_THROTTLE_STATUS_CHANGED:
249                     if (provider != null) {
250                         List<ThrottleStatus> statuses = (List<ThrottleStatus>) message.obj;
251                         provider.reportThrottleStatusChanged(statuses);
252                     }
253                     break;
254 
255                 case QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED:
256                     if (provider != null) {
257                         int transportType = (int) message.arg2;
258                         provider.reportEmergencyDataNetworkPreferredTransportChanged(transportType);
259                     }
260                     break;
261 
262                 case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
263                     if (provider != null) {
264                         provider.close();
265                         mProviders.remove(slotIndex);
266                     }
267                     break;
268 
269                 case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS:
270                     for (int i = 0; i < mProviders.size(); i++) {
271                         provider = mProviders.get(i);
272                         if (provider != null) {
273                             provider.close();
274                         }
275                     }
276                     mProviders.clear();
277                     break;
278 
279                 case QNS_UPDATE_QUALIFIED_NETWORKS:
280                     if (provider == null) break;
281                     provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
282                     break;
283             }
284         }
285     }
286 
287     /**
288      * Default constructor.
289      */
QualifiedNetworksService()290     public QualifiedNetworksService() {
291         mHandlerThread = new HandlerThread(TAG);
292         mHandlerThread.start();
293 
294         mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper());
295         log("Qualified networks service created");
296     }
297 
298     /**
299      * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
300      * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
301      * instances. The system will call this method after binding the qualified networks service for
302      * each active SIM slot index.
303      *
304      * @param slotIndex SIM slot index the qualified networks service associated with.
305      * @return Qualified networks service instance
306      */
307     @NonNull
onCreateNetworkAvailabilityProvider(int slotIndex)308     public abstract NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex);
309 
310     /** @hide */
311     @Override
onBind(Intent intent)312     public IBinder onBind(Intent intent) {
313         if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) {
314             loge("Unexpected intent " + intent);
315             return null;
316         }
317         return mBinder;
318     }
319 
320     /** @hide */
321     @Override
onUnbind(Intent intent)322     public boolean onUnbind(Intent intent) {
323         mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS).sendToTarget();
324         return false;
325     }
326 
327     /** @hide */
328     @Override
onDestroy()329     public void onDestroy() {
330         mHandlerThread.quit();
331     }
332 
333     /**
334      * A wrapper around IQualifiedNetworksService that forwards calls to implementations of
335      * {@link QualifiedNetworksService}.
336      */
337     private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
338         @Override
createNetworkAvailabilityProvider(int slotIndex, IQualifiedNetworksServiceCallback callback)339         public void createNetworkAvailabilityProvider(int slotIndex,
340                                                       IQualifiedNetworksServiceCallback callback) {
341             mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0,
342                     callback).sendToTarget();
343         }
344 
345         @Override
removeNetworkAvailabilityProvider(int slotIndex)346         public void removeNetworkAvailabilityProvider(int slotIndex) {
347             mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
348                     .sendToTarget();
349         }
350 
351         @Override
reportThrottleStatusChanged(int slotIndex, List<ThrottleStatus> statuses)352         public void reportThrottleStatusChanged(int slotIndex,
353                 List<ThrottleStatus> statuses) {
354             mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
355                     .sendToTarget();
356         }
357 
358         @Override
reportEmergencyDataNetworkPreferredTransportChanged(int slotIndex, @AccessNetworkConstants.TransportType int transportType)359         public void reportEmergencyDataNetworkPreferredTransportChanged(int slotIndex,
360                 @AccessNetworkConstants.TransportType int transportType) {
361             mHandler.obtainMessage(
362                     QNS_EMERGENCY_DATA_NETWORK_PREFERRED_TRANSPORT_CHANGED,
363                             slotIndex, transportType).sendToTarget();
364         }
365     }
366 
log(String s)367     private void log(String s) {
368         Rlog.d(TAG, s);
369     }
370 
loge(String s)371     private void loge(String s) {
372         Rlog.e(TAG, s);
373     }
374 }
375