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 com.android.internal.telephony.dataconnection; 18 19 import android.annotation.NonNull; 20 import android.content.BroadcastReceiver; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.ServiceConnection; 26 import android.content.pm.PackageManager; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.PersistableBundle; 30 import android.os.Registrant; 31 import android.os.RegistrantList; 32 import android.os.RemoteException; 33 import android.os.UserHandle; 34 import android.telephony.AccessNetworkConstants.AccessNetworkType; 35 import android.telephony.Annotation.ApnType; 36 import android.telephony.AnomalyReporter; 37 import android.telephony.CarrierConfigManager; 38 import android.telephony.data.ApnSetting; 39 import android.telephony.data.IQualifiedNetworksService; 40 import android.telephony.data.IQualifiedNetworksServiceCallback; 41 import android.telephony.data.QualifiedNetworksService; 42 import android.telephony.data.ThrottleStatus; 43 import android.text.TextUtils; 44 import android.util.SparseArray; 45 46 import com.android.internal.telephony.Phone; 47 import com.android.telephony.Rlog; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.HashSet; 52 import java.util.List; 53 import java.util.Set; 54 import java.util.UUID; 55 import java.util.stream.Collectors; 56 57 /** 58 * Access network manager manages the qualified/available networks for mobile data connection. 59 * It binds to the vendor's qualified networks service and actively monitors the qualified 60 * networks changes. 61 */ 62 public class AccessNetworksManager extends Handler { 63 private final String mLogTag; 64 private static final boolean DBG = false; 65 private final UUID mAnomalyUUID = UUID.fromString("c2d1a639-00e2-4561-9619-6acf37d90590"); 66 private String mLastBoundPackageName; 67 68 static final int[] SUPPORTED_APN_TYPES = { 69 ApnSetting.TYPE_DEFAULT, 70 ApnSetting.TYPE_MMS, 71 ApnSetting.TYPE_FOTA, 72 ApnSetting.TYPE_IMS, 73 ApnSetting.TYPE_CBS, 74 ApnSetting.TYPE_SUPL, 75 ApnSetting.TYPE_EMERGENCY, 76 ApnSetting.TYPE_XCAP 77 }; 78 79 private final Phone mPhone; 80 81 private final CarrierConfigManager mCarrierConfigManager; 82 83 private IQualifiedNetworksService mIQualifiedNetworksService; 84 85 private AccessNetworksManagerDeathRecipient mDeathRecipient; 86 87 private String mTargetBindingPackageName; 88 89 private QualifiedNetworksServiceConnection mServiceConnection; 90 91 // Available networks. Key is the APN type. 92 private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>(); 93 94 private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); 95 96 private final Set<DataThrottler> mDataThrottlers = new HashSet<>(); 97 98 private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { 99 @Override 100 public void onReceive(Context context, Intent intent) { 101 final String action = intent.getAction(); 102 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) 103 && mPhone.getPhoneId() == intent.getIntExtra( 104 CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { 105 // We should wait for carrier config changed event because the target binding 106 // package name can come from the carrier config. Note that we still get this event 107 // even when SIM is absent. 108 if (DBG) log("Carrier config changed. Try to bind qualified network service."); 109 bindQualifiedNetworksService(); 110 } 111 } 112 }; 113 114 /** 115 * Registers the data throttler in order to receive APN status changes. 116 * 117 * @param dataThrottler the data throttler to register 118 */ registerDataThrottler(DataThrottler dataThrottler)119 public void registerDataThrottler(DataThrottler dataThrottler) { 120 this.post(() -> { 121 QualifiedNetworksServiceConnection serviceConnection = mServiceConnection; 122 this.mDataThrottlers.add(dataThrottler); 123 if (serviceConnection != null) { 124 serviceConnection.registerDataThrottler(dataThrottler); 125 } 126 }); 127 } 128 129 /** 130 * Represents qualified network types list on a specific APN type. 131 */ 132 public static class QualifiedNetworks { 133 public final @ApnType int apnType; 134 // The qualified networks in preferred order. Each network is a AccessNetworkType. 135 public final int[] qualifiedNetworks; QualifiedNetworks(@pnType int apnType, int[] qualifiedNetworks)136 public QualifiedNetworks(@ApnType int apnType, int[] qualifiedNetworks) { 137 this.apnType = apnType; 138 this.qualifiedNetworks = qualifiedNetworks; 139 } 140 141 @Override toString()142 public String toString() { 143 List<String> accessNetworkStrings = new ArrayList<>(); 144 for (int network : qualifiedNetworks) { 145 accessNetworkStrings.add(AccessNetworkType.toString(network)); 146 } 147 return "[QualifiedNetworks: apnType=" 148 + ApnSetting.getApnTypeString(apnType) 149 + ", networks=" 150 + Arrays.stream(qualifiedNetworks) 151 .mapToObj(type -> AccessNetworkType.toString(type)) 152 .collect(Collectors.joining(",")) 153 + "]"; 154 } 155 } 156 157 private class AccessNetworksManagerDeathRecipient implements IBinder.DeathRecipient { 158 @Override binderDied()159 public void binderDied() { 160 // TODO: try to rebind the service. 161 String message = "Qualified network service " + mLastBoundPackageName + " died."; 162 loge(message); 163 AnomalyReporter.reportAnomaly(mAnomalyUUID, message); 164 } 165 } 166 167 private final class QualifiedNetworksServiceConnection implements ServiceConnection { 168 169 /** 170 * The APN throttle status callback is attached to the service connection so that they have 171 * the same life cycle. 172 */ 173 @NonNull 174 private final ThrottleStatusChangedCallback mThrottleStatusCallback; 175 QualifiedNetworksServiceConnection()176 QualifiedNetworksServiceConnection() { 177 mThrottleStatusCallback = new ThrottleStatusChangedCallback(); 178 } 179 180 @Override onServiceConnected(ComponentName name, IBinder service)181 public void onServiceConnected(ComponentName name, IBinder service) { 182 if (DBG) log("onServiceConnected " + name); 183 mIQualifiedNetworksService = IQualifiedNetworksService.Stub.asInterface(service); 184 mDeathRecipient = new AccessNetworksManagerDeathRecipient(); 185 mLastBoundPackageName = getQualifiedNetworksServicePackageName(); 186 187 try { 188 service.linkToDeath(mDeathRecipient, 0 /* flags */); 189 mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(), 190 new QualifiedNetworksServiceCallback()); 191 192 registerDataThrottlersFirstTime(); 193 194 } catch (RemoteException e) { 195 loge("Remote exception. " + e); 196 } 197 } 198 199 @Override onServiceDisconnected(ComponentName name)200 public void onServiceDisconnected(ComponentName name) { 201 if (DBG) log("onServiceDisconnected " + name); 202 unregisterForThrottleCallbacks(); 203 mTargetBindingPackageName = null; 204 } 205 206 /** 207 * Runs on all of the data throttlers when the service is connected 208 */ registerDataThrottlersFirstTime()209 private void registerDataThrottlersFirstTime() { 210 post(() -> { 211 for (DataThrottler dataThrottler : mDataThrottlers) { 212 dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); 213 } 214 }); 215 } 216 registerDataThrottler(DataThrottler dataThrottler)217 private void registerDataThrottler(DataThrottler dataThrottler) { 218 post(() -> { 219 dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); 220 }); 221 } 222 unregisterForThrottleCallbacks()223 private void unregisterForThrottleCallbacks() { 224 post(() -> { 225 for (DataThrottler dataThrottler : mDataThrottlers) { 226 dataThrottler.unregisterForThrottleStatusChanges(mThrottleStatusCallback); 227 } 228 }); 229 } 230 } 231 232 private class ThrottleStatusChangedCallback implements DataThrottler.Callback { 233 @Override onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses)234 public void onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses) { 235 post(() -> { 236 try { 237 List<ThrottleStatus> throttleStatusesBySlot = 238 throttleStatuses 239 .stream() 240 .filter(x -> x.getSlotIndex() == mPhone.getPhoneId()) 241 .collect(Collectors.toList()); 242 243 mIQualifiedNetworksService.reportThrottleStatusChanged(mPhone.getPhoneId(), 244 throttleStatusesBySlot); 245 } catch (Exception ex) { 246 loge("onThrottleStatusChanged", ex); 247 } 248 }); 249 } 250 } 251 252 private final class QualifiedNetworksServiceCallback extends 253 IQualifiedNetworksServiceCallback.Stub { 254 @Override onQualifiedNetworkTypesChanged(int apnTypes, int[] qualifiedNetworkTypes)255 public void onQualifiedNetworkTypesChanged(int apnTypes, int[] qualifiedNetworkTypes) { 256 log("onQualifiedNetworkTypesChanged. apnTypes = [" 257 + ApnSetting.getApnTypesStringFromBitmask(apnTypes) 258 + "], networks = [" + Arrays.stream(qualifiedNetworkTypes) 259 .mapToObj(i -> AccessNetworkType.toString(i)).collect(Collectors.joining(",")) 260 + "]"); 261 List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>(); 262 for (int supportedApnType : SUPPORTED_APN_TYPES) { 263 if ((apnTypes & supportedApnType) == supportedApnType) { 264 // TODO: Verify the preference from data settings manager to make sure the order 265 // of the networks do not violate users/carrier's preference. 266 if (mAvailableNetworks.get(supportedApnType) != null) { 267 if (Arrays.equals(mAvailableNetworks.get(supportedApnType), 268 qualifiedNetworkTypes)) { 269 log("Available networks for " 270 + ApnSetting.getApnTypesStringFromBitmask(supportedApnType) 271 + " not changed."); 272 continue; 273 } 274 } 275 mAvailableNetworks.put(supportedApnType, qualifiedNetworkTypes); 276 qualifiedNetworksList.add(new QualifiedNetworks(supportedApnType, 277 qualifiedNetworkTypes)); 278 } 279 } 280 281 if (!qualifiedNetworksList.isEmpty()) { 282 mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList); 283 } 284 } 285 } 286 287 /** 288 * Constructor 289 * 290 * @param phone The phone object 291 */ AccessNetworksManager(Phone phone)292 public AccessNetworksManager(Phone phone) { 293 mPhone = phone; 294 mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( 295 Context.CARRIER_CONFIG_SERVICE); 296 mLogTag = "ANM-" + mPhone.getPhoneId(); 297 298 IntentFilter intentFilter = new IntentFilter(); 299 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 300 try { 301 Context contextAsUser = phone.getContext().createPackageContextAsUser( 302 phone.getContext().getPackageName(), 0, UserHandle.ALL); 303 contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, 304 null /* broadcastPermission */, null); 305 } catch (PackageManager.NameNotFoundException e) { 306 loge("Package name not found: ", e); 307 } 308 bindQualifiedNetworksService(); 309 } 310 311 /** 312 * Find the qualified network service from configuration and binds to it. It reads the 313 * configuration from carrier config if it exists. If not, read it from resources. 314 */ bindQualifiedNetworksService()315 private void bindQualifiedNetworksService() { 316 post(() -> { 317 Intent intent = null; 318 String packageName = getQualifiedNetworksServicePackageName(); 319 String className = getQualifiedNetworksServiceClassName(); 320 321 if (DBG) log("Qualified network service package = " + packageName); 322 if (TextUtils.isEmpty(packageName)) { 323 loge("Can't find the binding package"); 324 return; 325 } 326 327 if (TextUtils.isEmpty(className)) { 328 intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE); 329 intent.setPackage(packageName); 330 } else { 331 ComponentName cm = new ComponentName(packageName, className); 332 intent = new Intent(QualifiedNetworksService.QUALIFIED_NETWORKS_SERVICE_INTERFACE) 333 .setComponent(cm); 334 } 335 336 if (TextUtils.equals(packageName, mTargetBindingPackageName)) { 337 if (DBG) log("Service " + packageName + " already bound or being bound."); 338 return; 339 } 340 341 if (mIQualifiedNetworksService != null 342 && mIQualifiedNetworksService.asBinder().isBinderAlive()) { 343 // Remove the network availability updater and then unbind the service. 344 try { 345 mIQualifiedNetworksService.removeNetworkAvailabilityProvider( 346 mPhone.getPhoneId()); 347 } catch (RemoteException e) { 348 loge("Cannot remove network availability updater. " + e); 349 } 350 351 mPhone.getContext().unbindService(mServiceConnection); 352 } 353 354 try { 355 mServiceConnection = new QualifiedNetworksServiceConnection(); 356 log("bind to " + packageName); 357 if (!mPhone.getContext().bindService(intent, mServiceConnection, 358 Context.BIND_AUTO_CREATE)) { 359 loge("Cannot bind to the qualified networks service."); 360 return; 361 } 362 mTargetBindingPackageName = packageName; 363 } catch (Exception e) { 364 loge("Cannot bind to the qualified networks service. Exception: " + e); 365 } 366 }); 367 } 368 369 /** 370 * Get the qualified network service package. 371 * 372 * @return package name of the qualified networks service package. Return empty string when in 373 * legacy mode (i.e. Dedicated IWLAN data/network service is not supported). 374 */ getQualifiedNetworksServicePackageName()375 private String getQualifiedNetworksServicePackageName() { 376 // Read package name from the resource 377 String packageName = mPhone.getContext().getResources().getString( 378 com.android.internal.R.string.config_qualified_networks_service_package); 379 380 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 381 382 if (b != null) { 383 // If carrier config overrides it, use the one from carrier config 384 String carrierConfigPackageName = b.getString(CarrierConfigManager 385 .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); 386 if (!TextUtils.isEmpty(carrierConfigPackageName)) { 387 if (DBG) log("Found carrier config override " + carrierConfigPackageName); 388 packageName = carrierConfigPackageName; 389 } 390 } 391 392 return packageName; 393 } 394 395 /** 396 * Get the qualified network service class name. 397 * 398 * @return class name of the qualified networks service package. 399 */ getQualifiedNetworksServiceClassName()400 private String getQualifiedNetworksServiceClassName() { 401 // Read package name from the resource 402 String className = mPhone.getContext().getResources().getString( 403 com.android.internal.R.string.config_qualified_networks_service_class); 404 405 PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); 406 407 if (b != null) { 408 // If carrier config overrides it, use the one from carrier config 409 String carrierConfigClassName = b.getString(CarrierConfigManager 410 .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); 411 if (!TextUtils.isEmpty(carrierConfigClassName)) { 412 if (DBG) log("Found carrier config override " + carrierConfigClassName); 413 className = carrierConfigClassName; 414 } 415 } 416 417 return className; 418 } 419 getQualifiedNetworksList()420 private @NonNull List<QualifiedNetworks> getQualifiedNetworksList() { 421 List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>(); 422 for (int i = 0; i < mAvailableNetworks.size(); i++) { 423 qualifiedNetworksList.add(new QualifiedNetworks(mAvailableNetworks.keyAt(i), 424 mAvailableNetworks.valueAt(i))); 425 } 426 427 return qualifiedNetworksList; 428 } 429 430 /** 431 * Register for qualified networks changed event. 432 * 433 * @param h The target to post the event message to. 434 * @param what The event. 435 */ registerForQualifiedNetworksChanged(Handler h, int what)436 public void registerForQualifiedNetworksChanged(Handler h, int what) { 437 if (h != null) { 438 Registrant r = new Registrant(h, what, null); 439 mQualifiedNetworksChangedRegistrants.add(r); 440 441 // Notify for the first time if there is already something in the available network 442 // list. 443 if (mAvailableNetworks.size() != 0) { 444 r.notifyResult(getQualifiedNetworksList()); 445 } 446 } 447 } 448 449 /** 450 * Unregister for qualified networks changed event. 451 * 452 * @param h The handler 453 */ unregisterForQualifiedNetworksChanged(Handler h)454 public void unregisterForQualifiedNetworksChanged(Handler h) { 455 if (h != null) { 456 mQualifiedNetworksChangedRegistrants.remove(h); 457 } 458 } 459 log(String s)460 private void log(String s) { 461 Rlog.d(mLogTag, s); 462 } 463 loge(String s)464 private void loge(String s) { 465 Rlog.e(mLogTag, s); 466 } 467 loge(String s, Exception ex)468 private void loge(String s, Exception ex) { 469 Rlog.e(mLogTag, s, ex); 470 } 471 472 } 473