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