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