• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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