1 /* 2 * Copyright (C) 2016 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 package com.android.internal.telephony; 17 18 import android.annotation.NonNull; 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.pm.PackageManager; 24 import android.os.PersistableBundle; 25 import android.os.UserHandle; 26 import android.telephony.AccessNetworkConstants; 27 import android.telephony.Annotation.NetworkType; 28 import android.telephony.CarrierConfigManager; 29 import android.telephony.NetworkRegistrationInfo; 30 import android.telephony.ServiceState; 31 import android.util.SparseArray; 32 import android.util.SparseIntArray; 33 34 import com.android.telephony.Rlog; 35 36 import java.util.Arrays; 37 38 /** 39 * This class loads configuration from CarrierConfig and uses it to determine 40 * what RATs are within a ratcheting family. For example all the HSPA/HSDPA/HSUPA RATs. 41 * Then, until reset the class will only ratchet upwards within the family (order 42 * determined by the CarrierConfig data). The ServiceStateTracker will reset this 43 * on cell-change. 44 */ 45 public class RatRatcheter { 46 private final static String LOG_TAG = "RilRatcheter"; 47 48 /** 49 * This is a map of RAT types -> RAT families for rapid lookup. 50 * The RAT families are defined by RAT type -> RAT Rank SparseIntArrays, so 51 * we can compare the priorities of two RAT types by comparing the values 52 * stored in the SparseIntArrays, higher values are higher priority. 53 */ 54 private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>(); 55 56 private final Phone mPhone; 57 58 /** 59 * Updates the ServiceState with a new set of cell bandwidths IFF the new bandwidth list has a 60 * higher aggregate bandwidth. 61 * 62 * @return Whether the bandwidths were updated. 63 */ updateBandwidths(int[] bandwidths, ServiceState serviceState)64 public static boolean updateBandwidths(int[] bandwidths, ServiceState serviceState) { 65 if (bandwidths == null) { 66 return false; 67 } 68 69 int ssAggregateBandwidth = Arrays.stream(serviceState.getCellBandwidths()).sum(); 70 int newAggregateBandwidth = Arrays.stream(bandwidths).sum(); 71 72 if (newAggregateBandwidth > ssAggregateBandwidth) { 73 serviceState.setCellBandwidths(bandwidths); 74 return true; 75 } 76 77 return false; 78 } 79 80 /** Constructor */ RatRatcheter(Phone phone)81 public RatRatcheter(Phone phone) { 82 mPhone = phone; 83 84 IntentFilter intentFilter = new IntentFilter(); 85 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 86 try { 87 Context contextAsUser = phone.getContext().createPackageContextAsUser( 88 phone.getContext().getPackageName(), 0, UserHandle.ALL); 89 contextAsUser.registerReceiver(mConfigChangedReceiver, 90 intentFilter, null /* broadcastPermission */, null); 91 } catch (PackageManager.NameNotFoundException e) { 92 Rlog.e(LOG_TAG, "Package name not found: " + e.getMessage()); 93 } 94 resetRatFamilyMap(); 95 } 96 ratchetRat(@etworkType int oldNetworkType, @NetworkType int newNetworkType)97 private @NetworkType int ratchetRat(@NetworkType int oldNetworkType, 98 @NetworkType int newNetworkType) { 99 int oldRat = ServiceState.networkTypeToRilRadioTechnology(oldNetworkType); 100 int newRat = ServiceState.networkTypeToRilRadioTechnology(newNetworkType); 101 synchronized (mRatFamilyMap) { 102 final SparseIntArray oldFamily = mRatFamilyMap.get(oldRat); 103 if (oldFamily == null) { 104 return newNetworkType; 105 } 106 107 final SparseIntArray newFamily = mRatFamilyMap.get(newRat); 108 if (newFamily != oldFamily) { 109 return newNetworkType; 110 } 111 112 // now go with the higher of the two 113 final int oldRatRank = newFamily.get(oldRat, -1); 114 final int newRatRank = newFamily.get(newRat, -1); 115 return ServiceState.rilRadioTechnologyToNetworkType( 116 oldRatRank > newRatRank ? oldRat : newRat); 117 } 118 } 119 120 /** 121 * Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. 122 * 123 * Ensure that a device on the same cell reports the best-seen capability to the user. 124 */ ratchet(@onNull ServiceState oldSS, @NonNull ServiceState newSS)125 public void ratchet(@NonNull ServiceState oldSS, @NonNull ServiceState newSS) { 126 // Different rat family, don't need rat ratchet and update cell bandwidths. 127 if (!isSameRatFamily(oldSS, newSS)) { 128 Rlog.e(LOG_TAG, "Same cell cannot have different RAT Families. Likely bug."); 129 return; 130 } 131 132 final int[] domains = { 133 NetworkRegistrationInfo.DOMAIN_CS, NetworkRegistrationInfo.DOMAIN_PS}; 134 for (int domain : domains) { 135 NetworkRegistrationInfo oldNri = oldSS.getNetworkRegistrationInfo( 136 domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 137 NetworkRegistrationInfo newNri = newSS.getNetworkRegistrationInfo( 138 domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 139 140 int newNetworkType = ratchetRat(oldNri.getAccessNetworkTechnology(), 141 newNri.getAccessNetworkTechnology()); 142 newNri.setAccessNetworkTechnology(newNetworkType); 143 if (oldNri.isUsingCarrierAggregation()) newNri.setIsUsingCarrierAggregation(true); 144 newSS.addNetworkRegistrationInfo(newNri); 145 } 146 147 // Ratchet Cell Bandwidths 148 updateBandwidths(oldSS.getCellBandwidths(), newSS); 149 } 150 isSameRatFamily(ServiceState ss1, ServiceState ss2)151 private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) { 152 synchronized (mRatFamilyMap) { 153 // Either the two technologies are the same or their families must be non-null 154 // and the same. 155 int dataRat1 = ServiceState.networkTypeToRilRadioTechnology( 156 ss1.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, 157 AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 158 .getAccessNetworkTechnology()); 159 int dataRat2 = ServiceState.networkTypeToRilRadioTechnology( 160 ss2.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, 161 AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 162 .getAccessNetworkTechnology()); 163 164 // The api getAccessNetworkTechnology@NetworkRegistrationInfo always returns LTE though 165 // data rat is LTE CA. Because it uses mIsUsingCarrierAggregation to indicate whether 166 // it is LTE CA or not. However, we need its actual data rat to check if they are the 167 // same family. So convert it to LTE CA. 168 if (dataRat1 == ServiceState.RIL_RADIO_TECHNOLOGY_LTE 169 && ss1.isUsingCarrierAggregation()) { 170 dataRat1 = ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; 171 } 172 173 if (dataRat2 == ServiceState.RIL_RADIO_TECHNOLOGY_LTE 174 && ss2.isUsingCarrierAggregation()) { 175 dataRat2 = ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; 176 } 177 178 if (dataRat1 == dataRat2) return true; 179 if (mRatFamilyMap.get(dataRat1) == null) { 180 return false; 181 } 182 return mRatFamilyMap.get(dataRat1) == mRatFamilyMap.get(dataRat2); 183 } 184 } 185 186 private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { 187 @Override 188 public void onReceive(Context context, Intent intent) { 189 final String action = intent.getAction(); 190 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { 191 resetRatFamilyMap(); 192 } 193 } 194 }; 195 resetRatFamilyMap()196 private void resetRatFamilyMap() { 197 synchronized(mRatFamilyMap) { 198 mRatFamilyMap.clear(); 199 200 final CarrierConfigManager configManager = (CarrierConfigManager) 201 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 202 if (configManager == null) return; 203 PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); 204 if (b == null) return; 205 206 // Reads an array of strings, eg: 207 // ["GPRS, EDGE", "EVDO, EVDO_A, EVDO_B", "HSPA, HSDPA, HSUPA, HSPAP"] 208 // Each string defines a family and the order of rats within the string express 209 // the priority of the RAT within the family (ie, we'd move up to later-listed RATs, but 210 // not down). 211 String[] ratFamilies = b.getStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES); 212 if (ratFamilies == null) return; 213 for (String ratFamily : ratFamilies) { 214 String[] rats = ratFamily.split(","); 215 if (rats.length < 2) continue; 216 SparseIntArray currentFamily = new SparseIntArray(rats.length); 217 int pos = 0; 218 for (String ratString : rats) { 219 int ratInt; 220 try { 221 ratInt = Integer.parseInt(ratString.trim()); 222 } catch (NumberFormatException e) { 223 Rlog.e(LOG_TAG, "NumberFormatException on " + ratString); 224 break; 225 } 226 if (mRatFamilyMap.get(ratInt) != null) { 227 Rlog.e(LOG_TAG, "RAT listed twice: " + ratString); 228 break; 229 } 230 currentFamily.put(ratInt, pos++); 231 mRatFamilyMap.put(ratInt, currentFamily); 232 } 233 } 234 } 235 } 236 } 237