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