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.os.PersistableBundle; 24 import android.os.UserHandle; 25 import android.telephony.AccessNetworkConstants; 26 import android.telephony.CarrierConfigManager; 27 import android.telephony.NetworkRegistrationInfo; 28 import android.telephony.Rlog; 29 import android.telephony.ServiceState; 30 import android.telephony.TelephonyManager.NetworkType; 31 import android.util.SparseArray; 32 import android.util.SparseIntArray; 33 34 import java.util.Arrays; 35 36 /** 37 * This class loads configuration from CarrierConfig and uses it to determine 38 * what RATs are within a ratcheting family. For example all the HSPA/HSDPA/HSUPA RATs. 39 * Then, until reset the class will only ratchet upwards within the family (order 40 * determined by the CarrierConfig data). The ServiceStateTracker will reset this 41 * on cell-change. 42 */ 43 public class RatRatcheter { 44 private final static String LOG_TAG = "RilRatcheter"; 45 46 /** 47 * This is a map of RAT types -> RAT families for rapid lookup. 48 * The RAT families are defined by RAT type -> RAT Rank SparseIntArrays, so 49 * we can compare the priorities of two RAT types by comparing the values 50 * stored in the SparseIntArrays, higher values are higher priority. 51 */ 52 private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>(); 53 54 private final Phone mPhone; 55 private boolean mVoiceRatchetEnabled = true; 56 private boolean mDataRatchetEnabled = true; 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 phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL, 87 intentFilter, null, null); 88 resetRatFamilyMap(); 89 } 90 ratchetRat(@etworkType int oldNetworkType, @NetworkType int newNetworkType)91 private @NetworkType int ratchetRat(@NetworkType int oldNetworkType, 92 @NetworkType int newNetworkType) { 93 int oldRat = ServiceState.networkTypeToRilRadioTechnology(oldNetworkType); 94 int newRat = ServiceState.networkTypeToRilRadioTechnology(newNetworkType); 95 synchronized (mRatFamilyMap) { 96 final SparseIntArray oldFamily = mRatFamilyMap.get(oldRat); 97 if (oldFamily == null) { 98 return newNetworkType; 99 } 100 101 final SparseIntArray newFamily = mRatFamilyMap.get(newRat); 102 if (newFamily != oldFamily) { 103 return newNetworkType; 104 } 105 106 // now go with the higher of the two 107 final int oldRatRank = newFamily.get(oldRat, -1); 108 final int newRatRank = newFamily.get(newRat, -1); 109 return ServiceState.rilRadioTechnologyToNetworkType( 110 oldRatRank > newRatRank ? oldRat : newRat); 111 } 112 } 113 114 /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */ ratchet(@onNull ServiceState oldSS, @NonNull ServiceState newSS, boolean locationChange)115 public void ratchet(@NonNull ServiceState oldSS, @NonNull ServiceState newSS, 116 boolean locationChange) { 117 if (!locationChange && isSameRatFamily(oldSS, newSS)) { 118 updateBandwidths(oldSS.getCellBandwidths(), newSS); 119 } 120 // temporarily disable rat ratchet on location change. 121 if (locationChange) { 122 mVoiceRatchetEnabled = false; 123 mDataRatchetEnabled = false; 124 return; 125 } 126 127 boolean newUsingCA = oldSS.isUsingCarrierAggregation() 128 || newSS.isUsingCarrierAggregation() 129 || newSS.getCellBandwidths().length > 1; 130 NetworkRegistrationInfo oldCsNri = oldSS.getNetworkRegistrationInfo( 131 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 132 NetworkRegistrationInfo newCsNri = newSS.getNetworkRegistrationInfo( 133 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 134 if (mVoiceRatchetEnabled) { 135 int newPsNetworkType = ratchetRat(oldCsNri.getAccessNetworkTechnology(), 136 newCsNri.getAccessNetworkTechnology()); 137 newCsNri.setAccessNetworkTechnology(newPsNetworkType); 138 newSS.addNetworkRegistrationInfo(newCsNri); 139 } else if (oldCsNri.getAccessNetworkTechnology() != oldCsNri.getAccessNetworkTechnology()) { 140 // resume rat ratchet on following rat change within the same location 141 mVoiceRatchetEnabled = true; 142 } 143 144 NetworkRegistrationInfo oldPsNri = oldSS.getNetworkRegistrationInfo( 145 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 146 NetworkRegistrationInfo newPsNri = newSS.getNetworkRegistrationInfo( 147 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 148 if (mDataRatchetEnabled) { 149 int newPsNetworkType = ratchetRat(oldPsNri.getAccessNetworkTechnology(), 150 newPsNri.getAccessNetworkTechnology()); 151 newPsNri.setAccessNetworkTechnology(newPsNetworkType); 152 newSS.addNetworkRegistrationInfo(newPsNri); 153 } else if (oldPsNri.getAccessNetworkTechnology() != newPsNri.getAccessNetworkTechnology()) { 154 // resume rat ratchet on following rat change within the same location 155 mDataRatchetEnabled = true; 156 } 157 158 newSS.setIsUsingCarrierAggregation(newUsingCA); 159 } 160 isSameRatFamily(ServiceState ss1, ServiceState ss2)161 private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) { 162 synchronized (mRatFamilyMap) { 163 // Either the two technologies are the same or their families must be non-null 164 // and the same. 165 int dataRat1 = ServiceState.networkTypeToRilRadioTechnology( 166 ss1.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, 167 AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 168 .getAccessNetworkTechnology()); 169 int dataRat2 = ServiceState.networkTypeToRilRadioTechnology( 170 ss2.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, 171 AccessNetworkConstants.TRANSPORT_TYPE_WWAN) 172 .getAccessNetworkTechnology()); 173 174 if (dataRat1 == dataRat2) return true; 175 if (mRatFamilyMap.get(dataRat1) == null) { 176 return false; 177 } 178 return mRatFamilyMap.get(dataRat1) == mRatFamilyMap.get(dataRat2); 179 } 180 } 181 182 private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { 183 @Override 184 public void onReceive(Context context, Intent intent) { 185 final String action = intent.getAction(); 186 if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { 187 resetRatFamilyMap(); 188 } 189 } 190 }; 191 resetRatFamilyMap()192 private void resetRatFamilyMap() { 193 synchronized(mRatFamilyMap) { 194 mRatFamilyMap.clear(); 195 196 final CarrierConfigManager configManager = (CarrierConfigManager) 197 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 198 if (configManager == null) return; 199 PersistableBundle b = configManager.getConfig(); 200 if (b == null) return; 201 202 // Reads an array of strings, eg: 203 // ["GPRS, EDGE", "EVDO, EVDO_A, EVDO_B", "HSPA, HSDPA, HSUPA, HSPAP"] 204 // Each string defines a family and the order of rats within the string express 205 // the priority of the RAT within the family (ie, we'd move up to later-listed RATs, but 206 // not down). 207 String[] ratFamilies = b.getStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES); 208 if (ratFamilies == null) return; 209 for (String ratFamily : ratFamilies) { 210 String[] rats = ratFamily.split(","); 211 if (rats.length < 2) continue; 212 SparseIntArray currentFamily = new SparseIntArray(rats.length); 213 int pos = 0; 214 for (String ratString : rats) { 215 int ratInt; 216 try { 217 ratInt = Integer.parseInt(ratString.trim()); 218 } catch (NumberFormatException e) { 219 Rlog.e(LOG_TAG, "NumberFormatException on " + ratString); 220 break; 221 } 222 if (mRatFamilyMap.get(ratInt) != null) { 223 Rlog.e(LOG_TAG, "RAT listed twice: " + ratString); 224 break; 225 } 226 currentFamily.put(ratInt, pos++); 227 mRatFamilyMap.put(ratInt, currentFamily); 228 } 229 } 230 } 231 } 232 } 233