• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
72     private final HandlerThread mHandlerThread;
73 
74     private final QualifiedNetworksServiceHandler mHandler;
75 
76     private final SparseArray<NetworkAvailabilityProvider> mProviders = new SparseArray<>();
77 
78     /** @hide */
79     @VisibleForTesting
80     public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();
81 
82     /**
83      * The abstract class of the network availability provider implementation. The vendor qualified
84      * network service must extend this class to report the available networks for data
85      * connection setup. Note that each instance of network availability provider is associated with
86      * one physical SIM slot.
87      */
88     public abstract class NetworkAvailabilityProvider implements AutoCloseable {
89         private final int mSlotIndex;
90 
91         private IQualifiedNetworksServiceCallback mCallback;
92 
93         /**
94          * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array
95          * of available networks.
96          */
97         private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>();
98 
99         /**
100          * Constructor
101          * @param slotIndex SIM slot index the network availability provider associated with.
102          */
NetworkAvailabilityProvider(int slotIndex)103         public NetworkAvailabilityProvider(int slotIndex) {
104             mSlotIndex = slotIndex;
105         }
106 
107         /**
108          * @return SIM slot index the network availability provider associated with.
109          */
getSlotIndex()110         public final int getSlotIndex() {
111             return mSlotIndex;
112         }
113 
registerForQualifiedNetworkTypesChanged( IQualifiedNetworksServiceCallback callback)114         private void registerForQualifiedNetworkTypesChanged(
115                 IQualifiedNetworksServiceCallback callback) {
116             mCallback = callback;
117 
118             // Force sending the qualified networks upon registered.
119             if (mCallback != null) {
120                 for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) {
121                     try {
122                         mCallback.onQualifiedNetworkTypesChanged(
123                                 mQualifiedNetworkTypesList.keyAt(i),
124                                 mQualifiedNetworkTypesList.valueAt(i));
125                     } catch (RemoteException e) {
126                         loge("Failed to call onQualifiedNetworksChanged. " + e);
127                     }
128                 }
129             }
130         }
131 
132         /**
133          * Update the suggested qualified networks list. Network availability provider must invoke
134          * this method whenever the suggested qualified networks changes. If this method is never
135          * invoked for certain APN types, then frameworks uses its own logic to determine the
136          * transport to setup the data network.
137          *
138          * For example, QNS can suggest frameworks setting up IMS data network on IWLAN by
139          * specifying {@link ApnSetting#TYPE_IMS} with a list containing
140          * {@link AccessNetworkType#IWLAN}.
141          *
142          * If QNS considers multiple access networks qualified for certain APN type, it can
143          * suggest frameworks by specifying the APN type with multiple access networks in the list,
144          * for example {{@link AccessNetworkType#EUTRAN}, {@link AccessNetworkType#IWLAN}}.
145          * Frameworks will then first attempt to setup data on LTE network, and If the device moves
146          * from LTE to UMTS, then frameworks will perform handover the data network to the second
147          * preferred access network if available.
148          *
149          * If the {@code qualifiedNetworkTypes} list is empty, it means QNS has no suggestion to the
150          * frameworks, and for that APN type frameworks will route the corresponding network
151          * requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
152          *
153          * @param apnTypes APN type(s) of the qualified networks. This must be a bitmask combination
154          * of {@link ApnType}. The same qualified networks will be applicable to all APN types
155          * specified here.
156          * @param qualifiedNetworkTypes List of access network types which are qualified for data
157          * connection setup for {@code apnTypes} in the preferred order. Empty list means QNS has no
158          * suggestion to the frameworks, and for that APN type frameworks will route the
159          * corresponding network requests to {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}.
160          *
161          * If one of the element is invalid, for example, {@link AccessNetworkType#UNKNOWN}, then
162          * this operation becomes a no-op.
163          */
updateQualifiedNetworkTypes( @pnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes)164         public final void updateQualifiedNetworkTypes(
165                 @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
166             int[] qualifiedNetworkTypesArray =
167                     qualifiedNetworkTypes.stream().mapToInt(i->i).toArray();
168             mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes,
169                     qualifiedNetworkTypesArray).sendToTarget();
170         }
171 
onUpdateQualifiedNetworkTypes(@pnType int apnTypes, int[] qualifiedNetworkTypes)172         private void onUpdateQualifiedNetworkTypes(@ApnType int apnTypes,
173                                                    int[] qualifiedNetworkTypes) {
174             mQualifiedNetworkTypesList.put(apnTypes, qualifiedNetworkTypes);
175             if (mCallback != null) {
176                 try {
177                     mCallback.onQualifiedNetworkTypesChanged(apnTypes, qualifiedNetworkTypes);
178                 } catch (RemoteException e) {
179                     loge("Failed to call onQualifiedNetworksChanged. " + e);
180                 }
181             }
182         }
183 
184         /**
185          * The framework calls this method when the throttle status of an APN changes.
186          *
187          * This method is meant to be overridden.
188          *
189          * @param statuses the statuses that have changed
190          */
reportThrottleStatusChanged(@onNull List<ThrottleStatus> statuses)191         public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
192             Log.d(TAG, "reportThrottleStatusChanged: statuses size=" + statuses.size());
193         }
194 
195         /**
196          * Called when the qualified networks provider is removed. The extended class should
197          * implement this method to perform cleanup works.
198          */
199         @Override
close()200         public abstract void close();
201     }
202 
203     private class QualifiedNetworksServiceHandler extends Handler {
QualifiedNetworksServiceHandler(Looper looper)204         QualifiedNetworksServiceHandler(Looper looper) {
205             super(looper);
206         }
207 
208         @Override
handleMessage(Message message)209         public void handleMessage(Message message) {
210             IQualifiedNetworksServiceCallback callback;
211             final int slotIndex = message.arg1;
212             NetworkAvailabilityProvider provider = mProviders.get(slotIndex);
213 
214             switch (message.what) {
215                 case QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER:
216                     if (mProviders.get(slotIndex) != null) {
217                         loge("Network availability provider for slot " + slotIndex
218                                 + " already existed.");
219                         return;
220                     }
221 
222                     provider = onCreateNetworkAvailabilityProvider(slotIndex);
223                     if (provider != null) {
224                         mProviders.put(slotIndex, provider);
225 
226                         callback = (IQualifiedNetworksServiceCallback) message.obj;
227                         provider.registerForQualifiedNetworkTypesChanged(callback);
228                     } else {
229                         loge("Failed to create network availability provider. slot index = "
230                                 + slotIndex);
231                     }
232                     break;
233                 case QNS_APN_THROTTLE_STATUS_CHANGED:
234                     if (provider != null) {
235                         List<ThrottleStatus> statuses = (List<ThrottleStatus>) message.obj;
236                         provider.reportThrottleStatusChanged(statuses);
237                     }
238                     break;
239 
240                 case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
241                     if (provider != null) {
242                         provider.close();
243                         mProviders.remove(slotIndex);
244                     }
245                     break;
246 
247                 case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS:
248                     for (int i = 0; i < mProviders.size(); i++) {
249                         provider = mProviders.get(i);
250                         if (provider != null) {
251                             provider.close();
252                         }
253                     }
254                     mProviders.clear();
255                     break;
256 
257                 case QNS_UPDATE_QUALIFIED_NETWORKS:
258                     if (provider == null) break;
259                     provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
260                     break;
261             }
262         }
263     }
264 
265     /**
266      * Default constructor.
267      */
QualifiedNetworksService()268     public QualifiedNetworksService() {
269         mHandlerThread = new HandlerThread(TAG);
270         mHandlerThread.start();
271 
272         mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper());
273         log("Qualified networks service created");
274     }
275 
276     /**
277      * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
278      * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
279      * instances. The system will call this method after binding the qualified networks service for
280      * each active SIM slot index.
281      *
282      * @param slotIndex SIM slot index the qualified networks service associated with.
283      * @return Qualified networks service instance
284      */
285     @NonNull
onCreateNetworkAvailabilityProvider(int slotIndex)286     public abstract NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex);
287 
288     /** @hide */
289     @Override
onBind(Intent intent)290     public IBinder onBind(Intent intent) {
291         if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) {
292             loge("Unexpected intent " + intent);
293             return null;
294         }
295         return mBinder;
296     }
297 
298     /** @hide */
299     @Override
onUnbind(Intent intent)300     public boolean onUnbind(Intent intent) {
301         mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS).sendToTarget();
302         return false;
303     }
304 
305     /** @hide */
306     @Override
onDestroy()307     public void onDestroy() {
308         mHandlerThread.quit();
309     }
310 
311     /**
312      * A wrapper around IQualifiedNetworksService that forwards calls to implementations of
313      * {@link QualifiedNetworksService}.
314      */
315     private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
316         @Override
createNetworkAvailabilityProvider(int slotIndex, IQualifiedNetworksServiceCallback callback)317         public void createNetworkAvailabilityProvider(int slotIndex,
318                                                       IQualifiedNetworksServiceCallback callback) {
319             mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0,
320                     callback).sendToTarget();
321         }
322 
323         @Override
removeNetworkAvailabilityProvider(int slotIndex)324         public void removeNetworkAvailabilityProvider(int slotIndex) {
325             mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
326                     .sendToTarget();
327         }
328 
329         @Override
reportThrottleStatusChanged(int slotIndex, List<ThrottleStatus> statuses)330         public void reportThrottleStatusChanged(int slotIndex,
331                 List<ThrottleStatus> statuses) {
332             mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
333                     .sendToTarget();
334         }
335     }
336 
log(String s)337     private void log(String s) {
338         Rlog.d(TAG, s);
339     }
340 
loge(String s)341     private void loge(String s) {
342         Rlog.e(TAG, s);
343     }
344 }
345