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