Home | History | Annotate | Download | only in telephony
      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.content.BroadcastReceiver;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.os.PersistableBundle;
     23 import android.os.UserHandle;
     24 import android.telephony.CarrierConfigManager;
     25 import android.telephony.Rlog;
     26 import android.telephony.ServiceState;
     27 import android.util.SparseArray;
     28 import android.util.SparseIntArray;
     29 
     30 import java.util.Arrays;
     31 
     32 /**
     33  * This class loads configuration from CarrierConfig and uses it to determine
     34  * what RATs are within a ratcheting family.  For example all the HSPA/HSDPA/HSUPA RATs.
     35  * Then, until reset the class will only ratchet upwards within the family (order
     36  * determined by the CarrierConfig data).  The ServiceStateTracker will reset this
     37  * on cell-change.
     38  */
     39 public class RatRatcheter {
     40     private final static String LOG_TAG = "RilRatcheter";
     41 
     42     /**
     43      * This is a map of RAT types -> RAT families for rapid lookup.
     44      * The RAT families are defined by RAT type -> RAT Rank SparseIntArrays, so
     45      * we can compare the priorities of two RAT types by comparing the values
     46      * stored in the SparseIntArrays, higher values are higher priority.
     47      */
     48     private final SparseArray<SparseIntArray> mRatFamilyMap = new SparseArray<>();
     49 
     50     private final Phone mPhone;
     51     private boolean mVoiceRatchetEnabled = true;
     52     private boolean mDataRatchetEnabled = true;
     53 
     54     /**
     55      * Updates the ServiceState with a new set of cell bandwidths IFF the new bandwidth list has a
     56      * higher aggregate bandwidth.
     57      *
     58      * @return Whether the bandwidths were updated.
     59      */
     60     public static boolean updateBandwidths(int[] bandwidths, ServiceState serviceState) {
     61         if (bandwidths == null) {
     62             return false;
     63         }
     64 
     65         int ssAggregateBandwidth = Arrays.stream(serviceState.getCellBandwidths()).sum();
     66         int newAggregateBandwidth = Arrays.stream(bandwidths).sum();
     67 
     68         if (newAggregateBandwidth > ssAggregateBandwidth) {
     69             serviceState.setCellBandwidths(bandwidths);
     70             return true;
     71         }
     72 
     73         return false;
     74     }
     75 
     76     /** Constructor */
     77     public RatRatcheter(Phone phone) {
     78         mPhone = phone;
     79 
     80         IntentFilter intentFilter = new IntentFilter();
     81         intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
     82         phone.getContext().registerReceiverAsUser(mConfigChangedReceiver, UserHandle.ALL,
     83                 intentFilter, null, null);
     84         resetRatFamilyMap();
     85     }
     86 
     87     private int ratchetRat(int oldRat, int newRat) {
     88         synchronized (mRatFamilyMap) {
     89             final SparseIntArray oldFamily = mRatFamilyMap.get(oldRat);
     90             if (oldFamily == null) return newRat;
     91 
     92             final SparseIntArray newFamily = mRatFamilyMap.get(newRat);
     93             if (newFamily != oldFamily) return newRat;
     94 
     95             // now go with the higher of the two
     96             final int oldRatRank = newFamily.get(oldRat, -1);
     97             final int newRatRank = newFamily.get(newRat, -1);
     98             return (oldRatRank > newRatRank ? oldRat : newRat);
     99         }
    100     }
    101 
    102     /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */
    103     public void ratchet(ServiceState oldSS, ServiceState newSS, boolean locationChange) {
    104         if (!locationChange && isSameRatFamily(oldSS, newSS)) {
    105             updateBandwidths(oldSS.getCellBandwidths(), newSS);
    106         }
    107         // temporarily disable rat ratchet on location change.
    108         if (locationChange) {
    109             mVoiceRatchetEnabled = false;
    110             mDataRatchetEnabled = false;
    111             return;
    112         }
    113         if (mVoiceRatchetEnabled) {
    114             int newVoiceRat = ratchetRat(oldSS.getRilVoiceRadioTechnology(),
    115                     newSS.getRilVoiceRadioTechnology());
    116             newSS.setRilVoiceRadioTechnology(newVoiceRat);
    117         } else if (oldSS.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology()) {
    118             // resume rat ratchet on following rat change within the same location
    119             mVoiceRatchetEnabled = true;
    120         }
    121 
    122         if (mDataRatchetEnabled) {
    123             int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
    124                     newSS.getRilDataRadioTechnology());
    125             newSS.setRilDataRadioTechnology(newDataRat);
    126         } else if (oldSS.getRilDataRadioTechnology() != newSS.getRilDataRadioTechnology()) {
    127             // resume rat ratchet on following rat change within the same location
    128             mDataRatchetEnabled = true;
    129         }
    130 
    131         boolean newUsingCA = oldSS.isUsingCarrierAggregation()
    132                 || newSS.isUsingCarrierAggregation()
    133                 || newSS.getCellBandwidths().length > 1;
    134         newSS.setIsUsingCarrierAggregation(newUsingCA);
    135     }
    136 
    137     private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) {
    138         synchronized (mRatFamilyMap) {
    139             // Either the two technologies are the same or their families must be non-null
    140             // and the same.
    141             if (ss1.getRilDataRadioTechnology() == ss2.getRilDataRadioTechnology()) return true;
    142             if (mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == null) return false;
    143             return mRatFamilyMap.get(ss1.getRilDataRadioTechnology())
    144                     == mRatFamilyMap.get(ss2.getRilDataRadioTechnology());
    145         }
    146     }
    147 
    148     private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() {
    149         @Override
    150         public void onReceive(Context context, Intent intent) {
    151             final String action = intent.getAction();
    152             if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
    153                 resetRatFamilyMap();
    154             }
    155         }
    156     };
    157 
    158     private void resetRatFamilyMap() {
    159         synchronized(mRatFamilyMap) {
    160             mRatFamilyMap.clear();
    161 
    162             final CarrierConfigManager configManager = (CarrierConfigManager)
    163                     mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
    164             if (configManager == null) return;
    165             PersistableBundle b = configManager.getConfig();
    166             if (b == null) return;
    167 
    168             // Reads an array of strings, eg:
    169             // ["GPRS, EDGE", "EVDO, EVDO_A, EVDO_B", "HSPA, HSDPA, HSUPA, HSPAP"]
    170             // Each string defines a family and the order of rats within the string express
    171             // the priority of the RAT within the family (ie, we'd move up to later-listed RATs, but
    172             // not down).
    173             String[] ratFamilies = b.getStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES);
    174             if (ratFamilies == null) return;
    175             for (String ratFamily : ratFamilies) {
    176                 String[] rats = ratFamily.split(",");
    177                 if (rats.length < 2) continue;
    178                 SparseIntArray currentFamily = new SparseIntArray(rats.length);
    179                 int pos = 0;
    180                 for (String ratString : rats) {
    181                     int ratInt;
    182                     try {
    183                         ratInt = Integer.parseInt(ratString.trim());
    184                     } catch (NumberFormatException e) {
    185                         Rlog.e(LOG_TAG, "NumberFormatException on " + ratString);
    186                         break;
    187                     }
    188                     if (mRatFamilyMap.get(ratInt) != null) {
    189                         Rlog.e(LOG_TAG, "RAT listed twice: " + ratString);
    190                         break;
    191                     }
    192                     currentFamily.put(ratInt, pos++);
    193                     mRatFamilyMap.put(ratInt, currentFamily);
    194                 }
    195             }
    196         }
    197     }
    198 }
    199