• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package com.android.internal.telephony;
18 
19 import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.os.AsyncResult;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Message;
28 import android.os.PersistableBundle;
29 import android.os.Registrant;
30 import android.os.RegistrantList;
31 import android.os.RemoteException;
32 import android.telephony.AccessNetworkConstants;
33 import android.telephony.AnomalyReporter;
34 import android.telephony.CarrierConfigManager;
35 import android.telephony.CellIdentity;
36 import android.telephony.CellIdentityLte;
37 import android.telephony.CellIdentityNr;
38 import android.telephony.CellInfo;
39 import android.telephony.CellSignalStrengthLte;
40 import android.telephony.CellSignalStrengthNr;
41 import android.telephony.ServiceState;
42 import android.telephony.SignalStrength;
43 import android.telephony.SignalStrengthUpdateRequest;
44 import android.telephony.SignalThresholdInfo;
45 import android.telephony.SubscriptionInfo;
46 import android.telephony.TelephonyManager;
47 import android.util.LocalLog;
48 import android.util.Pair;
49 
50 import com.android.internal.annotations.VisibleForTesting;
51 import com.android.internal.telephony.subscription.SubscriptionManagerService;
52 import com.android.internal.telephony.util.ArrayUtils;
53 import com.android.internal.telephony.util.TelephonyUtils;
54 import com.android.internal.util.IndentingPrintWriter;
55 import com.android.telephony.Rlog;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Iterator;
62 import java.util.List;
63 import java.util.NoSuchElementException;
64 import java.util.Objects;
65 import java.util.Set;
66 import java.util.TreeSet;
67 import java.util.UUID;
68 import java.util.concurrent.TimeUnit;
69 import java.util.concurrent.atomic.AtomicBoolean;
70 import java.util.regex.PatternSyntaxException;
71 
72 /**
73  * SignalStrengthController handles signal polling request and unsolicited signal strength update.
74  */
75 public class SignalStrengthController extends Handler {
76     private static final boolean DBG = false; /* STOPSHIP if true */
77     private static final String TAG = "SSCtr";
78 
79     private static final long SIGNAL_STRENGTH_REFRESH_THRESHOLD_IN_MS =
80             TimeUnit.SECONDS.toMillis(10);
81     /** Signal strength poll rate. */
82     private static final long POLL_PERIOD_MILLIS = TimeUnit.SECONDS.toMillis(20);
83     private static final int INVALID_ARFCN = -1;
84 
85     /** Required magnitude change between unsolicited SignalStrength reports. */
86     private static final int REPORTING_HYSTERESIS_DB = 2;
87     /** Minimum time between unsolicited SignalStrength reports. */
88     private static final int REPORTING_HYSTERESIS_MILLIS = 3000;
89     /**
90      * A threshold within which (inclusive) the application requested signal strength
91      * thresholds will be aligned with threholds set in advance (by system or other apps).
92      * Since the alignment applies to both directions, the value is set to halt of
93      * REPORTING_HYSTERESIS_DB to respect it while without introducing additional gaps for
94      * thresholds set by apps.
95      */
96     private static final int ALIGNMENT_HYSTERESIS_DB = 1;
97 
98     private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST       = 1;
99     private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST     = 2;
100     private static final int EVENT_ON_DEVICE_IDLE_STATE_CHANGED             = 3;
101     private static final int EVENT_RIL_CONNECTED                            = 4;
102     private static final int EVENT_RADIO_AVAILABLE                          = 5;
103     private static final int EVENT_GET_SIGNAL_STRENGTH                      = 6;
104     private static final int EVENT_POLL_SIGNAL_STRENGTH                     = 7;
105     private static final int EVENT_SIGNAL_STRENGTH_UPDATE                   = 8;
106     public static final int EVENT_POLL_SIGNAL_STRENGTH_DONE                = 9;
107     private static final int EVENT_SERVICE_STATE_CHANGED                    = 10;
108 
109     @NonNull
110     private final Phone mPhone;
111     @NonNull
112     private final CommandsInterface mCi;
113     @NonNull
114     private final RegistrantList mSignalStrengthChangedRegistrants = new RegistrantList();
115     @NonNull
116     private SignalStrength mSignalStrength;
117     private long mSignalStrengthUpdatedTime;
118     @Nullable
119     private SignalStrength mLastSignalStrength = null;
120 
121     /**
122      * List of LTE EARFCNs (E-UTRAN Absolute Radio Frequency Channel Number,
123      * Reference: 3GPP TS 36.104 5.4.3)
124      * inclusive ranges for which the lte rsrp boost is applied
125      */
126     @Nullable
127     private ArrayList<Pair<Integer, Integer>> mEarfcnPairListForRsrpBoost = null;
128     /**
129      * Offset which is reduced from the rsrp threshold while calculating signal strength level.
130      */
131     private int mLteRsrpBoost = 0;
132     /**
133      * Ranges of NR ARFCNs (5G Absolute Radio Frequency Channel Number,
134      * Reference: 3GPP TS 38.104)
135      * inclusive ranges for which the corresponding nr rsrp boost is applied
136      */
137     @Nullable
138     private ArrayList<Pair<Integer, Integer>> mNrarfcnRangeListForRsrpBoost = null;
139     @Nullable
140     private int[] mNrRsrpBoost = null;
141     @NonNull
142     private final Object mRsrpBoostLock = new Object();
143 
144     @NonNull
145     private final List<SignalRequestRecord> mSignalRequestRecords = new ArrayList<>();
146 
147     @NonNull
148     private PersistableBundle mCarrierConfig;
149 
150     @NonNull
151     private final LocalLog mLocalLog = new LocalLog(64);
152 
153     private final AtomicBoolean mNTNConnected = new AtomicBoolean(false);
154 
SignalStrengthController(@onNull Phone phone)155     public SignalStrengthController(@NonNull Phone phone) {
156         mPhone = phone;
157         mCi = mPhone.mCi;
158 
159         mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
160         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
161         mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
162         setSignalStrengthDefaultValues();
163 
164         CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class);
165         mCarrierConfig = getCarrierConfig();
166         // Callback which directly handle config change should be executed on handler thread
167         if (ccm != null) {
168             ccm.registerCarrierConfigChangeListener(this::post,
169                     (slotIndex, subId, carrierId, specificCarrierId) ->
170                             onCarrierConfigurationChanged(slotIndex));
171         }
172 
173         mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
174     }
175 
176     @Override
handleMessage(Message msg)177     public void handleMessage(Message msg) {
178         if (DBG) log("received event " + msg.what);
179         AsyncResult ar;
180 
181         switch (msg.what) {
182             case EVENT_RIL_CONNECTED: // fall through
183             case EVENT_RADIO_AVAILABLE:
184                 onReset();
185                 break;
186             case EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST: {
187                 Pair<SignalRequestRecord, Message> pair =
188                         (Pair<SignalRequestRecord, Message>) msg.obj;
189                 SignalRequestRecord record = pair.first;
190                 Message onCompleted = pair.second;
191                 AsyncResult ret = AsyncResult.forMessage(onCompleted);
192 
193                 // TODO(b/177956310): Check subId to filter out old request until a better solution
194                 boolean dupRequest = mSignalRequestRecords.stream().anyMatch(
195                         srr -> srr.mCallingUid == record.mCallingUid
196                                 && srr.mSubId == record.mSubId);
197                 if (dupRequest) {
198                     ret.exception = new IllegalStateException(
199                             "setSignalStrengthUpdateRequest called again with same subId");
200                     onCompleted.sendToTarget();
201                     break;
202                 }
203 
204                 try {
205                     record.mRequest.getLiveToken().linkToDeath(record, 0);
206                 } catch (RemoteException | NullPointerException ex) {
207                     ret.exception = new IllegalStateException(
208                             "Signal request client is already dead.");
209                     onCompleted.sendToTarget();
210                     break;
211                 }
212 
213                 mSignalRequestRecords.add(record);
214 
215                 updateAlwaysReportSignalStrength();
216                 updateReportingCriteria();
217 
218                 onCompleted.sendToTarget();
219                 break;
220             }
221 
222             case EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST: {
223                 Pair<SignalRequestRecord, Message> pair =
224                         (Pair<SignalRequestRecord, Message>) msg.obj;
225                 SignalRequestRecord record = pair.first;
226                 Message onCompleted = pair.second;
227 
228                 // for loop with removal may cause ConcurrentModificationException
229                 Iterator<SignalRequestRecord> it = mSignalRequestRecords.iterator();
230                 while (it.hasNext()) {
231                     SignalRequestRecord srr = it.next();
232                     if (srr.mRequest.getLiveToken().equals(record.mRequest.getLiveToken())) {
233                         try {
234                             srr.mRequest.getLiveToken().unlinkToDeath(srr, 0);
235                         } catch (NoSuchElementException ignored) {
236                             // Either never linked or has already unlinked, ignore anyway
237                         }
238                         it.remove();
239                     }
240                 }
241 
242                 updateAlwaysReportSignalStrength();
243                 updateReportingCriteria();
244 
245                 if (onCompleted != null) {
246                     AsyncResult ret = AsyncResult.forMessage(onCompleted);
247                     onCompleted.sendToTarget();
248                 }
249                 break;
250             }
251 
252             case EVENT_ON_DEVICE_IDLE_STATE_CHANGED: {
253                 updateReportingCriteria();
254                 break;
255             }
256 
257             case EVENT_POLL_SIGNAL_STRENGTH_DONE: // fall through
258             case EVENT_GET_SIGNAL_STRENGTH: {
259                 // This callback is called when signal strength is polled
260                 // all by itself
261 
262                 if (!(mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON)) {
263                     // Polling will continue when radio turns back on
264                     return;
265                 }
266                 ar = (AsyncResult) msg.obj;
267                 onSignalStrengthResult(ar);
268                 break;
269             }
270 
271             case EVENT_POLL_SIGNAL_STRENGTH: {
272                 // Just poll signal strength...not part of pollState()
273 
274                 mCi.getSignalStrength(obtainMessage(EVENT_POLL_SIGNAL_STRENGTH_DONE));
275                 break;
276             }
277 
278             case EVENT_SIGNAL_STRENGTH_UPDATE: {
279                 // This is a notification from CommandsInterface.setOnSignalStrengthUpdate
280 
281                 ar = (AsyncResult) msg.obj;
282                 onSignalStrengthResult(ar);
283                 break;
284             }
285 
286             case EVENT_SERVICE_STATE_CHANGED: {
287                 onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result);
288                 break;
289             }
290 
291             default:
292                 log("Unhandled message with number: " + msg.what);
293                 break;
294         }
295     }
296 
dispose()297     void dispose() {
298         mCi.unSetOnSignalStrengthUpdate(this);
299     }
300 
301     /**
302      * Called when RIL is connected during boot up or after modem restart. Set the default criteria
303      * so that modem can start with default state before updated criteria is ready.
304      */
onReset()305     private void onReset() {
306         setDefaultSignalStrengthReportingCriteria();
307     }
308 
getSignalStrengthFromCi()309     void getSignalStrengthFromCi() {
310         mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
311     }
312 
313     /**
314      * Send signal-strength-changed notification if changed. Called for both solicited and
315      * unsolicited signal strength updates.
316      */
onSignalStrengthResult(@onNull AsyncResult ar)317     private void onSignalStrengthResult(@NonNull AsyncResult ar) {
318         // This signal is used for both voice and data radio signal so parse all fields.
319 
320         SignalStrength signalStrength;
321         if ((ar.exception == null) && (ar.result != null)) {
322             signalStrength = (SignalStrength) ar.result;
323         } else {
324             loge("onSignalStrengthResult() Exception from RIL : " + ar.exception);
325             signalStrength = new SignalStrength();
326         }
327         updateSignalStrength(signalStrength);
328     }
329 
330     /**
331      * Set {@code mSignalStrength} to the input argument {@code signalStrength}, update its level,
332      * and send signal-strength-changed notification if changed.
333      *
334      * @param signalStrength The new SignalStrength used for updating {@code mSignalStrength}.
335      */
updateSignalStrength(@onNull SignalStrength signalStrength)336     private void updateSignalStrength(@NonNull SignalStrength signalStrength) {
337         mSignalStrength = maybeOverrideSignalStrengthForTest(signalStrength);
338         ServiceStateTracker serviceStateTracker = mPhone.getServiceStateTracker();
339         if (serviceStateTracker != null) {
340             mSignalStrength.updateLevel(mCarrierConfig, serviceStateTracker.mSS);
341         } else {
342             loge("updateSignalStrength: serviceStateTracker is null");
343         }
344         mSignalStrengthUpdatedTime = System.currentTimeMillis();
345         notifySignalStrength();
346     }
347 
348     /**
349      * For debug test build, override signal strength for testing.
350      * @param original The real signal strength to use if not in testing mode.
351      * @return The signal strength to broadcast to the external.
352      */
maybeOverrideSignalStrengthForTest( @onNull SignalStrength original)353     @NonNull private SignalStrength maybeOverrideSignalStrengthForTest(
354             @NonNull SignalStrength original) {
355         return TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null
356                 ? Objects.requireNonNullElse(mPhone.getTelephonyTester()
357                 .getOverriddenSignalStrength(), original) : original;
358     }
359 
360     /**
361      * @return signal strength
362      */
363     @NonNull
getSignalStrength()364     public SignalStrength getSignalStrength() {
365         if (shouldRefreshSignalStrength()) {
366             log("getSignalStrength() refreshing signal strength.");
367             obtainMessage(EVENT_POLL_SIGNAL_STRENGTH).sendToTarget();
368         }
369         return mSignalStrength;
370     }
371 
shouldRefreshSignalStrength()372     private boolean shouldRefreshSignalStrength() {
373         long curTime = System.currentTimeMillis();
374 
375         // If last signal strength is older than 10 seconds, or somehow if curTime is smaller
376         // than mSignalStrengthUpdatedTime (system time update), it's considered stale.
377         boolean isStale = (mSignalStrengthUpdatedTime > curTime)
378                 || (curTime - mSignalStrengthUpdatedTime > SIGNAL_STRENGTH_REFRESH_THRESHOLD_IN_MS);
379         if (!isStale) return false;
380 
381         List<SubscriptionInfo> subInfoList = SubscriptionManagerService.getInstance()
382                 .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(),
383                         mPhone.getContext().getAttributionTag(), true/*isForAllProfile*/);
384 
385         if (!ArrayUtils.isEmpty(subInfoList)) {
386             for (SubscriptionInfo info : subInfoList) {
387                 // If we have an active opportunistic subscription whose data is IN_SERVICE,
388                 // we need to get signal strength to decide data switching threshold. In this case,
389                 // we poll latest signal strength from modem.
390                 if (info.isOpportunistic()) {
391                     TelephonyManager tm = TelephonyManager.from(mPhone.getContext())
392                             .createForSubscriptionId(info.getSubscriptionId());
393                     ServiceState ss = tm.getServiceState();
394                     if (ss != null
395                             && ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE) {
396                         return true;
397                     }
398                 }
399             }
400         }
401 
402         return false;
403     }
404 
405     /**
406      * Update signal strength reporting criteria from the carrier config
407      */
408     @VisibleForTesting
updateReportingCriteria()409     public void updateReportingCriteria() {
410         List<SignalThresholdInfo> signalThresholdInfos = new ArrayList<>();
411 
412         int[] gsmRssiThresholds = mCarrierConfig.getIntArray(
413                 CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY);
414         if (gsmRssiThresholds != null) {
415             signalThresholdInfos.add(
416                     validateAndCreateSignalThresholdInfo(
417                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
418                             gsmRssiThresholds,
419                             AccessNetworkThresholds.GERAN,
420                             AccessNetworkConstants.AccessNetworkType.GERAN,
421                             true));
422         }
423 
424         int[] wcdmaRscpThresholds = mCarrierConfig.getIntArray(
425                 CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
426         if (wcdmaRscpThresholds != null) {
427             signalThresholdInfos.add(
428                     validateAndCreateSignalThresholdInfo(
429                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP,
430                             wcdmaRscpThresholds,
431                             AccessNetworkThresholds.UTRAN,
432                             AccessNetworkConstants.AccessNetworkType.UTRAN,
433                             true));
434         }
435 
436         int lteMeasurementEnabled = mCarrierConfig.getInt(isUsingNonTerrestrialNetwork()
437                         ? CarrierConfigManager.KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT
438                         : CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
439                 CellSignalStrengthLte.USE_RSRP);
440         int[] lteRsrpThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork()
441                 ? CarrierConfigManager.KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY
442                 : CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY);
443         if (lteRsrpThresholds != null) {
444             signalThresholdInfos.add(
445                     validateAndCreateSignalThresholdInfo(
446                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP,
447                             lteRsrpThresholds,
448                             AccessNetworkThresholds.EUTRAN_RSRP,
449                             AccessNetworkConstants.AccessNetworkType.EUTRAN,
450                             (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRP) != 0));
451         }
452 
453         if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
454             int[] lteRsrqThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork()
455                     ? CarrierConfigManager.KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY :
456                     CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY);
457             if (lteRsrqThresholds != null) {
458                 signalThresholdInfos.add(
459                         validateAndCreateSignalThresholdInfo(
460                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ,
461                                 lteRsrqThresholds,
462                                 AccessNetworkThresholds.EUTRAN_RSRQ,
463                                 AccessNetworkConstants.AccessNetworkType.EUTRAN,
464                                 (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRQ) != 0));
465             }
466 
467             int[] lteRssnrThresholds = mCarrierConfig.getIntArray(isUsingNonTerrestrialNetwork()
468                     ? CarrierConfigManager.KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY :
469                     CarrierConfigManager.KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY);
470             if (lteRssnrThresholds != null) {
471                 signalThresholdInfos.add(
472                         validateAndCreateSignalThresholdInfo(
473                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR,
474                                 lteRssnrThresholds,
475                                 AccessNetworkThresholds.EUTRAN_RSSNR,
476                                 AccessNetworkConstants.AccessNetworkType.EUTRAN,
477                                 (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSSNR) != 0));
478             }
479 
480             int nrMeasurementEnabled = mCarrierConfig.getInt(CarrierConfigManager
481                     .KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, CellSignalStrengthNr.USE_SSRSRP);
482             int[] nrSsrsrpThresholds = mCarrierConfig.getIntArray(
483                     CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY);
484             if (nrSsrsrpThresholds != null) {
485                 signalThresholdInfos.add(
486                         validateAndCreateSignalThresholdInfo(
487                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP,
488                                 nrSsrsrpThresholds,
489                                 AccessNetworkThresholds.NGRAN_SSRSRP,
490                                 AccessNetworkConstants.AccessNetworkType.NGRAN,
491                                 (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSRSRP) != 0));
492             }
493 
494             int[] nrSsrsrqThresholds = mCarrierConfig.getIntArray(
495                     CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY);
496             if (nrSsrsrqThresholds != null) {
497                 signalThresholdInfos.add(
498                         validateAndCreateSignalThresholdInfo(
499                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
500                                 nrSsrsrqThresholds,
501                                 AccessNetworkThresholds.NGRAN_SSRSRQ,
502                                 AccessNetworkConstants.AccessNetworkType.NGRAN,
503                                 (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSRSRQ) != 0));
504             }
505 
506             int[] nrSssinrThresholds = mCarrierConfig.getIntArray(
507                     CarrierConfigManager.KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY);
508             if (nrSssinrThresholds != null) {
509                 signalThresholdInfos.add(
510                         validateAndCreateSignalThresholdInfo(
511                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR,
512                                 nrSssinrThresholds,
513                                 AccessNetworkThresholds.NGRAN_SSSINR,
514                                 AccessNetworkConstants.AccessNetworkType.NGRAN,
515                                 (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSSINR) != 0));
516             }
517 
518             int[] wcdmaEcnoThresholds = mCarrierConfig.getIntArray(
519                     CarrierConfigManager.KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY);
520             if (wcdmaEcnoThresholds != null) {
521                 signalThresholdInfos.add(
522                         validateAndCreateSignalThresholdInfo(
523                                 SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO,
524                                 wcdmaEcnoThresholds,
525                                 AccessNetworkThresholds.UTRAN_ECNO,
526                                 AccessNetworkConstants.AccessNetworkType.UTRAN,
527                                 false));
528             }
529 
530         }
531 
532         consolidatedAndSetReportingCriteria(signalThresholdInfos);
533     }
534 
setDefaultSignalStrengthReportingCriteria()535     private void setDefaultSignalStrengthReportingCriteria() {
536         List<SignalThresholdInfo> signalThresholdInfos = new ArrayList<>();
537 
538         signalThresholdInfos.add(
539                 createSignalThresholdsInfo(
540                         SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
541                         AccessNetworkThresholds.GERAN,
542                         AccessNetworkConstants.AccessNetworkType.GERAN,
543                         true));
544         signalThresholdInfos.add(
545                 createSignalThresholdsInfo(
546                         SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP,
547                         AccessNetworkThresholds.UTRAN,
548                         AccessNetworkConstants.AccessNetworkType.UTRAN,
549                         true));
550         signalThresholdInfos.add(
551                 createSignalThresholdsInfo(
552                         SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP,
553                         AccessNetworkThresholds.EUTRAN_RSRP,
554                         AccessNetworkConstants.AccessNetworkType.EUTRAN,
555                         true));
556         signalThresholdInfos.add(
557                 createSignalThresholdsInfo(
558                         SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
559                         AccessNetworkThresholds.CDMA2000,
560                         AccessNetworkConstants.AccessNetworkType.CDMA2000,
561                         true));
562 
563         if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
564             signalThresholdInfos.add(
565                     createSignalThresholdsInfo(
566                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ,
567                             AccessNetworkThresholds.EUTRAN_RSRQ,
568                             AccessNetworkConstants.AccessNetworkType.EUTRAN,
569                             false));
570             signalThresholdInfos.add(
571                     createSignalThresholdsInfo(
572                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR,
573                             AccessNetworkThresholds.EUTRAN_RSSNR,
574                             AccessNetworkConstants.AccessNetworkType.EUTRAN,
575                             true));
576 
577             // Defaultly we only need SSRSRP for NGRAN signal criteria reporting
578             signalThresholdInfos.add(
579                     createSignalThresholdsInfo(
580                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP,
581                             AccessNetworkThresholds.NGRAN_SSRSRP,
582                             AccessNetworkConstants.AccessNetworkType.NGRAN,
583                             true));
584             signalThresholdInfos.add(
585                     createSignalThresholdsInfo(
586                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
587                             AccessNetworkThresholds.NGRAN_SSRSRQ,
588                             AccessNetworkConstants.AccessNetworkType.NGRAN,
589                             false));
590             signalThresholdInfos.add(
591                     createSignalThresholdsInfo(
592                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR,
593                             AccessNetworkThresholds.NGRAN_SSSINR,
594                             AccessNetworkConstants.AccessNetworkType.NGRAN,
595                             false));
596             signalThresholdInfos.add(
597                     createSignalThresholdsInfo(
598                             SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO,
599                             AccessNetworkThresholds.UTRAN_ECNO,
600                             AccessNetworkConstants.AccessNetworkType.UTRAN,
601                             false));
602         }
603 
604         consolidatedAndSetReportingCriteria(signalThresholdInfos);
605     }
606 
consolidatedAndSetReportingCriteria( @onNull List<SignalThresholdInfo> signalThresholdInfos)607     private void consolidatedAndSetReportingCriteria(
608             @NonNull List<SignalThresholdInfo> signalThresholdInfos) {
609         List<SignalThresholdInfo> consolidatedSignalThresholdInfos = new ArrayList<>(
610                 signalThresholdInfos.size());
611         for (SignalThresholdInfo signalThresholdInfo : signalThresholdInfos) {
612             final int ran = signalThresholdInfo.getRadioAccessNetworkType();
613             final int measurementType = signalThresholdInfo.getSignalMeasurementType();
614             final boolean isEnabledForSystem =
615                     signalThresholdInfo.isEnabled() && shouldHonorSystemThresholds();
616             int[] consolidatedThresholds =
617                     getConsolidatedSignalThresholds(
618                             ran,
619                             measurementType,
620                             isEnabledForSystem
621                                     ? signalThresholdInfo.getThresholds()
622                                     : new int[]{},
623                             ALIGNMENT_HYSTERESIS_DB);
624             boolean isEnabledForAppRequest =
625                     shouldEnableSignalThresholdForAppRequest(
626                             ran,
627                             measurementType,
628                             mPhone.getSubId(),
629                             mPhone.isDeviceIdle());
630             int hysteresisDb = getMinimumHysteresisDb(isEnabledForAppRequest, ran, measurementType,
631                     consolidatedThresholds);
632             consolidatedSignalThresholdInfos.add(
633                     new SignalThresholdInfo.Builder()
634                             .setRadioAccessNetworkType(ran)
635                             .setSignalMeasurementType(measurementType)
636                             .setHysteresisMs(REPORTING_HYSTERESIS_MILLIS)
637                             .setHysteresisDb(hysteresisDb)
638                             .setThresholds(consolidatedThresholds, true /*isSystem*/)
639                             .setIsEnabled(isEnabledForSystem || isEnabledForAppRequest)
640                             .build());
641         }
642         mCi.setSignalStrengthReportingCriteria(consolidatedSignalThresholdInfos, null);
643 
644         localLog("setSignalStrengthReportingCriteria consolidatedSignalThresholdInfos="
645                         + consolidatedSignalThresholdInfos);
646     }
647 
648     /**
649      * Return the minimum hysteresis dB from all available sources:
650      * - system default
651      * - value set by client through API
652      * - threshold delta
653      */
654     @VisibleForTesting
getMinimumHysteresisDb(boolean isEnabledForAppRequest, int ran, int measurementType, final int[] consolidatedThresholdList)655     public int getMinimumHysteresisDb(boolean isEnabledForAppRequest, int ran, int measurementType,
656               final int[] consolidatedThresholdList) {
657 
658         int currHysteresisDb = getHysteresisDbFromCarrierConfig(ran, measurementType);
659 
660         if (isEnabledForAppRequest) {
661             // Get minimum hysteresisDb at api
662             int apiHysteresisDb =
663                     getHysteresisDbFromSignalThresholdInfoRequests(ran, measurementType);
664 
665             // Choose minimum of hysteresisDb between api Vs current system/cc value set
666             currHysteresisDb = Math.min(currHysteresisDb, apiHysteresisDb);
667 
668             // Hal Req: choose hysteresis db value to be smaller of smallest of threshold delta
669             currHysteresisDb =  computeHysteresisDbOnSmallestThresholdDelta(
670                     currHysteresisDb, consolidatedThresholdList);
671         }
672         return currHysteresisDb;
673     }
674 
675     /**
676      * Get the hysteresis db value from Signal Requests
677      * Note: Based on the current use case, there does not exist multile App signal threshold info
678      * requests with hysteresis db value, so this logic picks the latest hysteresis db value set.
679      *
680      * TODO(b/262655157): Support Multiple App Hysteresis DB value customisation
681      */
getHysteresisDbFromSignalThresholdInfoRequests( @ccessNetworkConstants.RadioAccessNetworkType int ran, @SignalThresholdInfo.SignalMeasurementType int measurement)682     private int getHysteresisDbFromSignalThresholdInfoRequests(
683             @AccessNetworkConstants.RadioAccessNetworkType int ran,
684             @SignalThresholdInfo.SignalMeasurementType int measurement) {
685         int apiHysteresisDb = REPORTING_HYSTERESIS_DB;
686         for (SignalRequestRecord record : mSignalRequestRecords) {
687             for (SignalThresholdInfo info : record.mRequest.getSignalThresholdInfos()) {
688                 if (isRanAndSignalMeasurementTypeMatch(ran, measurement, info)) {
689                     if (info.getHysteresisDb() >= 0) {
690                         apiHysteresisDb = info.getHysteresisDb();
691                     }
692                 }
693             }
694         }
695         return apiHysteresisDb;
696     }
697 
getHysteresisDbFromCarrierConfig(int ran, int measurement)698     private int getHysteresisDbFromCarrierConfig(int ran, int measurement) {
699         int configHysteresisDb = REPORTING_HYSTERESIS_DB;
700         String configKey = null;
701 
702         switch (ran) {
703             case AccessNetworkConstants.AccessNetworkType.GERAN:
704                 if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) {
705                     configKey = CarrierConfigManager.KEY_GERAN_RSSI_HYSTERESIS_DB_INT;
706                 }
707                 break;
708             case AccessNetworkConstants.AccessNetworkType.UTRAN:
709                 if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) {
710                     configKey = CarrierConfigManager.KEY_UTRAN_RSCP_HYSTERESIS_DB_INT;
711                 } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO) {
712                     configKey = CarrierConfigManager.KEY_UTRAN_ECNO_HYSTERESIS_DB_INT;
713                 }
714                 break;
715             case AccessNetworkConstants.AccessNetworkType.EUTRAN:
716                 if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) {
717                     configKey = CarrierConfigManager.KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT;
718                 } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) {
719                     configKey = CarrierConfigManager.KEY_EUTRAN_RSRQ_HYSTERESIS_DB_INT;
720                 } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) {
721                     configKey = CarrierConfigManager.KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT;
722                 }
723                 break;
724             case AccessNetworkConstants.AccessNetworkType.NGRAN:
725                 if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) {
726                     configKey = CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT;
727                 } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) {
728                     configKey = CarrierConfigManager.KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT;
729                 } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) {
730                     configKey = CarrierConfigManager.KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT;
731                 }
732                 break;
733             default:
734                 localLog("No matching configuration");
735         }
736         if (configKey != null) {
737             configHysteresisDb = mCarrierConfig.getInt(configKey, REPORTING_HYSTERESIS_DB);
738         }
739         return configHysteresisDb >= SignalThresholdInfo.HYSTERESIS_DB_MINIMUM
740                 ? configHysteresisDb : REPORTING_HYSTERESIS_DB;
741     }
742 
743     /**
744      * This method computes the hysteresis db value between smaller of the smallest Threshold Delta
745      * and system / cc / api hysteresis db value determined.
746      *
747      * @param currMinHysteresisDb  smaller value between system / cc / api hysteresis db value
748      * @param signalThresholdInfoArray consolidated threshold info with App request consolidated.
749      * @return current minimum hysteresis db value computed between above params.
750      *
751      */
computeHysteresisDbOnSmallestThresholdDelta( int currMinHysteresisDb, final int[] signalThresholdInfoArray)752     private int computeHysteresisDbOnSmallestThresholdDelta(
753             int currMinHysteresisDb, final int[] signalThresholdInfoArray) {
754         int index = 0;
755         if (signalThresholdInfoArray.length > 1) {
756             while (index != signalThresholdInfoArray.length - 1) {
757                 if (signalThresholdInfoArray[index + 1] - signalThresholdInfoArray[index]
758                         < currMinHysteresisDb) {
759                     currMinHysteresisDb =
760                             signalThresholdInfoArray[index + 1] - signalThresholdInfoArray[index];
761                 }
762                 index++;
763             }
764         }
765         return currMinHysteresisDb;
766     }
767 
setSignalStrengthDefaultValues()768     void setSignalStrengthDefaultValues() {
769         mSignalStrength = maybeOverrideSignalStrengthForTest(new SignalStrength());
770         mSignalStrengthUpdatedTime = System.currentTimeMillis();
771     }
772 
notifySignalStrength()773     void notifySignalStrength() {
774         if (!mSignalStrength.equals(mLastSignalStrength)) {
775             try {
776                 mSignalStrengthChangedRegistrants.notifyRegistrants();
777                 mPhone.notifySignalStrength();
778                 mLastSignalStrength = mSignalStrength;
779             } catch (NullPointerException ex) {
780                 loge("updateSignalStrength() Phone already destroyed: " + ex
781                         + "SignalStrength not notified");
782             }
783         }
784     }
785 
786     /**
787      * Register for SignalStrength changed.
788      * @param h Handler to notify
789      * @param what msg.what when the message is delivered
790      * @param obj msg.obj when the message is delivered
791      */
registerForSignalStrengthChanged(Handler h, int what, Object obj)792     public void registerForSignalStrengthChanged(Handler h, int what, Object obj) {
793         Registrant r = new Registrant(h, what, obj);
794         mSignalStrengthChangedRegistrants.add(r);
795     }
796 
797     /**
798      * Unregister for SignalStrength changed.
799      * @param h Handler to notify
800      */
unregisterForSignalStrengthChanged(Handler h)801     public void unregisterForSignalStrengthChanged(Handler h) {
802         mSignalStrengthChangedRegistrants.remove(h);
803     }
804 
805     /**
806      * Print the SignalStrengthController states into the given stream.
807      *
808      * @param fd The raw file descriptor that the dump is being sent to.
809      * @param pw A PrintWriter to which the dump is to be set.
810      * @param args Additional arguments to the dump request.
811      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)812     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
813         pw.println("SignalStrengthController - phoneId: " + mPhone.getPhoneId());
814         pw.println("SignalStrengthController - Log Begin ----");
815         mLocalLog.dump(fd, pw, args);
816         pw.println("SignalStrengthController - Log End ----");
817 
818         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
819         ipw.increaseIndent();
820         pw.println("mSignalRequestRecords=" + mSignalRequestRecords);
821         pw.println(" mLastSignalStrength=" + mLastSignalStrength);
822         pw.println(" mSignalStrength=" + mSignalStrength);
823         pw.println(" mLteRsrpBoost=" + mLteRsrpBoost);
824         pw.println(" mNrRsrpBoost=" + Arrays.toString(mNrRsrpBoost));
825         pw.println(" mEarfcnPairListForRsrpBoost=" + mEarfcnPairListForRsrpBoost);
826         pw.println(" mNrarfcnRangeListForRsrpBoost=" + mNrarfcnRangeListForRsrpBoost);
827         ipw.decreaseIndent();
828         ipw.flush();
829     }
830 
831     /**
832      * Set a new request to update the signal strength thresholds.
833      */
setSignalStrengthUpdateRequest(int subId, int callingUid, @NonNull SignalStrengthUpdateRequest request, @NonNull Message onCompleted)834     public void setSignalStrengthUpdateRequest(int subId, int callingUid,
835             @NonNull SignalStrengthUpdateRequest request, @NonNull Message onCompleted) {
836         SignalRequestRecord record = new SignalRequestRecord(subId, callingUid, request);
837         sendMessage(obtainMessage(EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST,
838                 new Pair<SignalRequestRecord, Message>(record, onCompleted)));
839 
840         localLog("setSignalStrengthUpdateRequest"
841                 + " subId=" + subId
842                 + " callingUid=" + callingUid
843                 + " request=" + request);
844     }
845 
846     /**
847      * Clear the previously set request.
848      */
clearSignalStrengthUpdateRequest(int subId, int callingUid, @NonNull SignalStrengthUpdateRequest request, @Nullable Message onCompleted)849     public void clearSignalStrengthUpdateRequest(int subId, int callingUid,
850             @NonNull SignalStrengthUpdateRequest request, @Nullable Message onCompleted) {
851         SignalRequestRecord record = new SignalRequestRecord(subId, callingUid, request);
852         sendMessage(obtainMessage(EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST,
853                 new Pair<SignalRequestRecord, Message>(record, onCompleted)));
854 
855         localLog("clearSignalStrengthUpdateRequest"
856                 + " subId=" + subId
857                 + " callingUid=" + callingUid
858                 + " request=" + request);
859     }
860 
861     /**
862      * Align all the qualified thresholds set from applications to the {@code systemThresholds}
863      * and consolidate a new thresholds array, follow rules below:
864      * 1. All threshold values (whose interval is guaranteed to be larger than hysteresis) in
865      *    {@code systemThresholds} will keep as it.
866      * 2. Any threshold from apps that has interval less than hysteresis from any threshold in
867      *    {@code systemThresholds} will be removed.
868      * 3. The target thresholds will be {@code systemThresholds} + all qualified thresholds from
869      *    apps, sorted in ascending order.
870      */
871     @VisibleForTesting
872     @NonNull
getConsolidatedSignalThresholds(int ran, int measurement, @Nullable int[] systemThresholds, int hysteresis)873     public int[] getConsolidatedSignalThresholds(int ran, int measurement,
874             @Nullable int[] systemThresholds, int hysteresis) {
875 
876         // TreeSet with comparator that will filter element with interval less than hysteresis
877         // from any current element
878         Set<Integer> target = new TreeSet<>((x, y) -> {
879             if (y >= x - hysteresis && y <= x + hysteresis) {
880                 return 0;
881             }
882             return Integer.compare(x, y);
883         });
884 
885         if (systemThresholds != null) {
886             for (int systemThreshold : systemThresholds) {
887                 target.add(systemThreshold);
888             }
889         }
890 
891         final boolean isDeviceIdle = mPhone.isDeviceIdle();
892         final int curSubId = mPhone.getSubId();
893         // The total number of record is small (10~15 tops). With each request has at most 5
894         // SignalThresholdInfo which has at most 8 thresholds arrays. So the nested loop should
895         // not be a concern here.
896         for (SignalRequestRecord record : mSignalRequestRecords) {
897             if (curSubId != record.mSubId
898                     || (isDeviceIdle && !record.mRequest.isReportingRequestedWhileIdle())) {
899                 continue;
900             }
901             for (SignalThresholdInfo info : record.mRequest.getSignalThresholdInfos()) {
902                 if (isRanAndSignalMeasurementTypeMatch(ran, measurement, info)) {
903                     for (int appThreshold : info.getThresholds()) {
904                         target.add(appThreshold);
905                     }
906                 }
907             }
908         }
909 
910         int[] targetArray = new int[target.size()];
911         int i = 0;
912         for (int element : target) {
913             targetArray[i++] = element;
914         }
915         return targetArray;
916     }
917 
918     /**
919      * Return true if system thresholds should be honored when consolidating.
920      */
921     @VisibleForTesting
shouldHonorSystemThresholds()922     public boolean shouldHonorSystemThresholds() {
923         if (!mPhone.isDeviceIdle()) {
924             return true;
925         }
926 
927         final int curSubId = mPhone.getSubId();
928         return mSignalRequestRecords.stream().anyMatch(
929                 srr -> curSubId == srr.mSubId
930                         && srr.mRequest.isSystemThresholdReportingRequestedWhileIdle());
931     }
932 
933     /**
934      * Get notified when device idle state changed
935      */
936     @VisibleForTesting
onDeviceIdleStateChanged(boolean isDeviceIdle)937     public void onDeviceIdleStateChanged(boolean isDeviceIdle) {
938         sendMessage(obtainMessage(EVENT_ON_DEVICE_IDLE_STATE_CHANGED, isDeviceIdle));
939 
940         localLog("onDeviceIdleStateChanged isDeviceIdle=" + isDeviceIdle);
941     }
942 
943     /**
944      * Return true if signal threshold should be enabled due to the apps requests.
945      */
946     @VisibleForTesting
shouldEnableSignalThresholdForAppRequest( @ccessNetworkConstants.RadioAccessNetworkType int ran, @SignalThresholdInfo.SignalMeasurementType int measurement, int subId, boolean isDeviceIdle)947     public boolean shouldEnableSignalThresholdForAppRequest(
948             @AccessNetworkConstants.RadioAccessNetworkType int ran,
949             @SignalThresholdInfo.SignalMeasurementType int measurement,
950             int subId,
951             boolean isDeviceIdle) {
952         for (SignalRequestRecord record : mSignalRequestRecords) {
953             if (subId != record.mSubId) {
954                 continue;
955             }
956             for (SignalThresholdInfo info : record.mRequest.getSignalThresholdInfos()) {
957                 if (isRanAndSignalMeasurementTypeMatch(ran, measurement, info)
958                         && (!isDeviceIdle || isSignalReportRequestedWhileIdle(record.mRequest))) {
959                     return true;
960                 }
961             }
962         }
963         return false;
964     }
965 
isRanAndSignalMeasurementTypeMatch( @ccessNetworkConstants.RadioAccessNetworkType int ran, @SignalThresholdInfo.SignalMeasurementType int measurement, @NonNull SignalThresholdInfo info)966     private static boolean isRanAndSignalMeasurementTypeMatch(
967             @AccessNetworkConstants.RadioAccessNetworkType int ran,
968             @SignalThresholdInfo.SignalMeasurementType int measurement,
969             @NonNull SignalThresholdInfo info) {
970         return ran == info.getRadioAccessNetworkType()
971                 && measurement == info.getSignalMeasurementType();
972     }
973 
isSignalReportRequestedWhileIdle( @onNull SignalStrengthUpdateRequest request)974     private static boolean isSignalReportRequestedWhileIdle(
975             @NonNull SignalStrengthUpdateRequest request) {
976         return request.isSystemThresholdReportingRequestedWhileIdle()
977                 || request.isReportingRequestedWhileIdle();
978     }
979 
980     /**
981      * Gets the carrier configuration values for a particular subscription.
982      *
983      * @return A {@link PersistableBundle} containing the config for the given subId,
984      *         or default values for an invalid subId.
985      */
986     @NonNull
getCarrierConfig()987     private PersistableBundle getCarrierConfig() {
988         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
989                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
990         if (configManager != null) {
991             // If an invalid subId is used, this bundle will contain default values.
992             PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId());
993             if (config != null) {
994                 return config;
995             }
996         }
997         // Return static default defined in CarrierConfigManager.
998         return CarrierConfigManager.getDefaultConfig();
999     }
1000 
1001     private class SignalRequestRecord implements IBinder.DeathRecipient {
1002         final int mSubId; // subId the request originally applied to
1003         final int mCallingUid;
1004         @NonNull
1005         final SignalStrengthUpdateRequest mRequest;
1006 
SignalRequestRecord(int subId, int uid, @NonNull SignalStrengthUpdateRequest request)1007         SignalRequestRecord(int subId, int uid, @NonNull SignalStrengthUpdateRequest request) {
1008             this.mCallingUid = uid;
1009             this.mSubId = subId;
1010             this.mRequest = request;
1011         }
1012 
1013         @Override
binderDied()1014         public void binderDied() {
1015             localLog("binderDied record=" + this);
1016             clearSignalStrengthUpdateRequest(mSubId, mCallingUid, mRequest, null /*onCompleted*/);
1017         }
1018 
1019         @Override
toString()1020         public String toString() {
1021             StringBuffer sb = new StringBuffer("SignalRequestRecord {");
1022             sb.append("mSubId=").append(mSubId);
1023             sb.append(" mCallingUid=").append(mCallingUid);
1024             sb.append(" mRequest=").append(mRequest).append("}");
1025             return sb.toString();
1026         }
1027     }
1028 
updateAlwaysReportSignalStrength()1029     private void updateAlwaysReportSignalStrength() {
1030         final int curSubId = mPhone.getSubId();
1031         boolean alwaysReport = mSignalRequestRecords.stream().anyMatch(
1032                 srr -> srr.mSubId == curSubId && isSignalReportRequestedWhileIdle(srr.mRequest));
1033 
1034         // TODO(b/177924721): TM#setAlwaysReportSignalStrength will be removed and we will not
1035         // worry about unset flag which was set by other client.
1036         mPhone.setAlwaysReportSignalStrength(alwaysReport);
1037     }
1038 
updateArfcnLists()1039     void updateArfcnLists() {
1040         synchronized (mRsrpBoostLock) {
1041             mLteRsrpBoost = mCarrierConfig.getInt(
1042                     CarrierConfigManager.KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
1043             String[] earfcnsStringArrayForRsrpBoost = mCarrierConfig.getStringArray(
1044                     CarrierConfigManager.KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY);
1045             mEarfcnPairListForRsrpBoost = convertEarfcnStringArrayToPairList(
1046                     earfcnsStringArrayForRsrpBoost);
1047 
1048             mNrRsrpBoost = mCarrierConfig.getIntArray(
1049                     CarrierConfigManager.KEY_NRARFCNS_RSRP_BOOST_INT_ARRAY);
1050             String[] nrarfcnsStringArrayForRsrpBoost = mCarrierConfig.getStringArray(
1051                     CarrierConfigManager.KEY_BOOSTED_NRARFCNS_STRING_ARRAY);
1052             mNrarfcnRangeListForRsrpBoost = convertEarfcnStringArrayToPairList(
1053                     nrarfcnsStringArrayForRsrpBoost);
1054 
1055             if ((mNrRsrpBoost == null && mNrarfcnRangeListForRsrpBoost != null)
1056                     || (mNrRsrpBoost != null && mNrarfcnRangeListForRsrpBoost == null)
1057                     || (mNrRsrpBoost != null && mNrarfcnRangeListForRsrpBoost != null
1058                     && mNrRsrpBoost.length != mNrarfcnRangeListForRsrpBoost.size())) {
1059                 loge("Invalid parameters for NR RSRP boost");
1060                 mNrRsrpBoost = null;
1061                 mNrarfcnRangeListForRsrpBoost = null;
1062             }
1063         }
1064     }
1065 
1066     // package private access from ServiceStateTracker
1067     // TODO(b/219572311): Maintains ArfcnRsrpBoost here only without forwarding by ServiceState
updateServiceStateArfcnRsrpBoost(@onNull ServiceState serviceState, @Nullable CellIdentity cellIdentity)1068     void updateServiceStateArfcnRsrpBoost(@NonNull ServiceState serviceState,
1069             @Nullable CellIdentity cellIdentity) {
1070         if (cellIdentity == null) return;
1071 
1072         int rsrpBoost = 0;
1073         int arfcn;
1074 
1075         synchronized (mRsrpBoostLock) {
1076             switch (cellIdentity.getType()) {
1077                 case CellInfo.TYPE_LTE:
1078                     arfcn = ((CellIdentityLte) cellIdentity).getEarfcn();
1079                     if (arfcn != INVALID_ARFCN
1080                             && containsEarfcnInEarfcnRange(mEarfcnPairListForRsrpBoost,
1081                             arfcn) != -1) {
1082                         rsrpBoost = mLteRsrpBoost;
1083                     }
1084                     break;
1085                 case CellInfo.TYPE_NR:
1086                     arfcn = ((CellIdentityNr) cellIdentity).getNrarfcn();
1087                     if (arfcn != INVALID_ARFCN) {
1088                         int index = containsEarfcnInEarfcnRange(mNrarfcnRangeListForRsrpBoost,
1089                                 arfcn);
1090                         if (index != -1 && mNrRsrpBoost != null) {
1091                             rsrpBoost = mNrRsrpBoost[index];
1092                         }
1093                     }
1094                     break;
1095                 default:
1096                     break;
1097             }
1098         }
1099         serviceState.setArfcnRsrpBoost(rsrpBoost);
1100     }
1101 
1102     /**
1103      * Checks if the provided earfcn falls within the range of earfcns.
1104      *
1105      * return int index in earfcnPairList if earfcn falls within the provided range; -1 otherwise.
1106      */
containsEarfcnInEarfcnRange( @ullable ArrayList<Pair<Integer, Integer>> earfcnPairList, int earfcn)1107     private static int containsEarfcnInEarfcnRange(
1108             @Nullable ArrayList<Pair<Integer, Integer>> earfcnPairList, int earfcn) {
1109         int index = 0;
1110         if (earfcnPairList != null) {
1111             for (Pair<Integer, Integer> earfcnPair : earfcnPairList) {
1112                 if ((earfcn >= earfcnPair.first) && (earfcn <= earfcnPair.second)) {
1113                     return index;
1114                 }
1115                 index++;
1116             }
1117         }
1118 
1119         return -1;
1120     }
1121 
1122     /**
1123      * Convert the earfcnStringArray to list of pairs.
1124      *
1125      * Format of the earfcnsList is expected to be {"erafcn1_start-earfcn1_end",
1126      * "earfcn2_start-earfcn2_end" ... }
1127      */
1128     @Nullable
convertEarfcnStringArrayToPairList( @ullable String[] earfcnsList)1129     private static ArrayList<Pair<Integer, Integer>> convertEarfcnStringArrayToPairList(
1130             @Nullable String[] earfcnsList) {
1131         ArrayList<Pair<Integer, Integer>> earfcnPairList = new ArrayList<Pair<Integer, Integer>>();
1132 
1133         if (earfcnsList != null) {
1134             int earfcnStart;
1135             int earfcnEnd;
1136             for (int i = 0; i < earfcnsList.length; i++) {
1137                 try {
1138                     String[] earfcns = earfcnsList[i].split("-");
1139                     if (earfcns.length != 2) {
1140                         if (DBG) {
1141                             log("Invalid earfcn range format");
1142                         }
1143                         return null;
1144                     }
1145 
1146                     earfcnStart = Integer.parseInt(earfcns[0]);
1147                     earfcnEnd = Integer.parseInt(earfcns[1]);
1148 
1149                     if (earfcnStart > earfcnEnd) {
1150                         if (DBG) {
1151                             log("Invalid earfcn range format");
1152                         }
1153                         return null;
1154                     }
1155 
1156                     earfcnPairList.add(new Pair<Integer, Integer>(earfcnStart, earfcnEnd));
1157                 } catch (PatternSyntaxException pse) {
1158                     if (DBG) {
1159                         log("Invalid earfcn range format");
1160                     }
1161                     return null;
1162                 } catch (NumberFormatException nfe) {
1163                     if (DBG) {
1164                         log("Invalid earfcn number format");
1165                     }
1166                     return null;
1167                 }
1168             }
1169         }
1170 
1171         return earfcnPairList;
1172     }
1173 
onCarrierConfigurationChanged(int slotIndex)1174     private void onCarrierConfigurationChanged(int slotIndex) {
1175         if (slotIndex != mPhone.getPhoneId()) return;
1176 
1177         mCarrierConfig = getCarrierConfig();
1178         log("Carrier Config changed.");
1179 
1180         updateArfcnLists();
1181         updateReportingCriteria();
1182         updateSignalStrength(new SignalStrength(mSignalStrength));
1183     }
1184 
createSignalThresholdsInfo( int measurementType, @NonNull int[] thresholds, int ran, boolean isEnabled)1185     private static SignalThresholdInfo createSignalThresholdsInfo(
1186             int measurementType, @NonNull int[] thresholds, int ran, boolean isEnabled) {
1187         return new SignalThresholdInfo.Builder()
1188                 .setSignalMeasurementType(measurementType)
1189                 .setThresholds(thresholds)
1190                 .setRadioAccessNetworkType(ran)
1191                 .setIsEnabled(isEnabled)
1192                 .build();
1193     }
1194 
1195     /**
1196      * Validate the provided signal {@code thresholds} info and fall back to use the
1197      * {@code defaultThresholds} and report anomaly if invalid to prevent crashing Phone.
1198      */
validateAndCreateSignalThresholdInfo( int measurementType, @NonNull int[] thresholds, @NonNull int[] defaultThresholds, int ran, boolean isEnabled)1199     private static SignalThresholdInfo validateAndCreateSignalThresholdInfo(
1200             int measurementType, @NonNull int[] thresholds, @NonNull int[] defaultThresholds,
1201             int ran, boolean isEnabled) {
1202         SignalThresholdInfo signalThresholdInfo;
1203         try {
1204             signalThresholdInfo = new SignalThresholdInfo.Builder()
1205                     .setSignalMeasurementType(measurementType)
1206                     .setThresholds(thresholds)
1207                     .setRadioAccessNetworkType(ran)
1208                     .setIsEnabled(isEnabled)
1209                     .build();
1210         // TODO(b/295236831): only catch IAE when phone global exception handler is introduced.
1211         // Although SignalThresholdInfo only throws IAE for invalid carrier configs, we catch
1212         // all exception to prevent crashing phone before global exception handler is available.
1213         } catch (Exception e) {
1214             signalThresholdInfo = new SignalThresholdInfo.Builder()
1215                     .setSignalMeasurementType(measurementType)
1216                     .setThresholds(defaultThresholds)
1217                     .setRadioAccessNetworkType(ran)
1218                     .setIsEnabled(isEnabled)
1219                     .build();
1220 
1221             AnomalyReporter.reportAnomaly(
1222                     UUID.fromString("28232bc4-78ff-447e-b597-7c054c802407"),
1223                     "Invalid parameter to generate SignalThresholdInfo: "
1224                             + "measurementType=" + measurementType
1225                             + ", thresholds=" + Arrays.toString(thresholds)
1226                             + ", RAN=" + ran
1227                             + ", isEnabled=" + isEnabled
1228                             + ". Replaced with default thresholds: " + Arrays.toString(
1229                             defaultThresholds));
1230         }
1231         return signalThresholdInfo;
1232     }
1233 
1234     /**
1235      * dBm thresholds that correspond to changes in signal strength indications.
1236      */
1237     private static final class AccessNetworkThresholds {
1238 
1239         /**
1240          * List of dBm thresholds for GERAN {@link AccessNetworkConstants.AccessNetworkType}.
1241          *
1242          * Calculated from GSM asu level thresholds - TS 27.007 Sec 8.5
1243          */
1244         public static final int[] GERAN = new int[]{
1245                 -109,
1246                 -103,
1247                 -97,
1248                 -89,
1249         };
1250 
1251         /**
1252          * List of default dBm thresholds for UTRAN
1253          * {@link AccessNetworkConstants.AccessNetworkType}.
1254          *
1255          * These thresholds are taken from the WCDMA RSCP defaults in {@link CarrierConfigManager}.
1256          * See TS 27.007 Sec 8.69.
1257          */
1258         public static final int[] UTRAN = new int[]{
1259                 -114, /* SIGNAL_STRENGTH_POOR */
1260                 -104, /* SIGNAL_STRENGTH_MODERATE */
1261                 -94,  /* SIGNAL_STRENGTH_GOOD */
1262                 -84   /* SIGNAL_STRENGTH_GREAT */
1263         };
1264 
1265         /**
1266          * List of default dBm RSRP thresholds for EUTRAN
1267          * {@link AccessNetworkConstants.AccessNetworkType}.
1268          *
1269          * These thresholds are taken from the LTE RSRP defaults in {@link CarrierConfigManager}.
1270          */
1271         public static final int[] EUTRAN_RSRP = new int[]{
1272                 -128, /* SIGNAL_STRENGTH_POOR */
1273                 -118, /* SIGNAL_STRENGTH_MODERATE */
1274                 -108, /* SIGNAL_STRENGTH_GOOD */
1275                 -98,  /* SIGNAL_STRENGTH_GREAT */
1276         };
1277 
1278         /**
1279          * List of default dB RSRQ thresholds for EUTRAN
1280          * {@link AccessNetworkConstants.AccessNetworkType}.
1281          *
1282          * These thresholds are taken from the LTE RSRQ defaults in {@link CarrierConfigManager}.
1283          */
1284         public static final int[] EUTRAN_RSRQ = new int[]{
1285                 -20,  /* SIGNAL_STRENGTH_POOR */
1286                 -17,  /* SIGNAL_STRENGTH_MODERATE */
1287                 -14,  /* SIGNAL_STRENGTH_GOOD */
1288                 -11   /* SIGNAL_STRENGTH_GREAT */
1289         };
1290 
1291         /**
1292          * List of default dB RSSNR thresholds for EUTRAN
1293          * {@link AccessNetworkConstants.AccessNetworkType}.
1294          *
1295          * These thresholds are taken from the LTE RSSNR defaults in {@link CarrierConfigManager}.
1296          */
1297         public static final int[] EUTRAN_RSSNR = new int[]{
1298                 -3,  /* SIGNAL_STRENGTH_POOR */
1299                 1,   /* SIGNAL_STRENGTH_MODERATE */
1300                 5,   /* SIGNAL_STRENGTH_GOOD */
1301                 13   /* SIGNAL_STRENGTH_GREAT */
1302         };
1303 
1304         /**
1305          * List of dBm thresholds for CDMA2000 {@link AccessNetworkConstants.AccessNetworkType}.
1306          *
1307          * These correspond to EVDO level thresholds.
1308          */
1309         public static final int[] CDMA2000 = new int[]{
1310                 -105,
1311                 -90,
1312                 -75,
1313                 -65
1314         };
1315 
1316         /**
1317          * List of dB thresholds for NGRAN {@link AccessNetworkConstants.AccessNetworkType} SSRSRP
1318          */
1319         public static final int[] NGRAN_SSRSRP = new int[]{
1320                 -110, /* SIGNAL_STRENGTH_POOR */
1321                 -90, /* SIGNAL_STRENGTH_MODERATE */
1322                 -80, /* SIGNAL_STRENGTH_GOOD */
1323                 -65,  /* SIGNAL_STRENGTH_GREAT */
1324         };
1325 
1326         /**
1327          * List of dB thresholds for NGRAN {@link AccessNetworkConstants.AccessNetworkType} SSRSRQ
1328          */
1329         public static final int[] NGRAN_SSRSRQ = new int[]{
1330                 -31, /* SIGNAL_STRENGTH_POOR */
1331                 -19, /* SIGNAL_STRENGTH_MODERATE */
1332                 -7, /* SIGNAL_STRENGTH_GOOD */
1333                 6  /* SIGNAL_STRENGTH_GREAT */
1334         };
1335 
1336         /**
1337          * List of dB thresholds for NGRAN {@link AccessNetworkConstants.AccessNetworkType} SSSINR
1338          */
1339         public static final int[] NGRAN_SSSINR = new int[]{
1340                 -5, /* SIGNAL_STRENGTH_POOR */
1341                 5, /* SIGNAL_STRENGTH_MODERATE */
1342                 15, /* SIGNAL_STRENGTH_GOOD */
1343                 30  /* SIGNAL_STRENGTH_GREAT */
1344         };
1345 
1346         /**
1347          * List of dBm thresholds for UTRAN {@link AccessNetworkConstants.AccessNetworkType} ECNO
1348          */
1349         public static final int[] UTRAN_ECNO = new int[]{
1350                 -24, /* SIGNAL_STRENGTH_POOR */
1351                 -14, /* SIGNAL_STRENGTH_MODERATE */
1352                 -6, /* SIGNAL_STRENGTH_GOOD */
1353                 1  /* SIGNAL_STRENGTH_GREAT */
1354         };
1355     }
1356 
onServiceStateChanged(ServiceState state)1357     private void onServiceStateChanged(ServiceState state) {
1358         if (state.getState() != ServiceState.STATE_IN_SERVICE) {
1359             return;
1360         }
1361 
1362         if (mNTNConnected.get() != state.isUsingNonTerrestrialNetwork()) {
1363             log("onServiceStateChanged: update it to " + state.isUsingNonTerrestrialNetwork());
1364             updateReportingCriteria();
1365             mNTNConnected.set(state.isUsingNonTerrestrialNetwork());
1366         }
1367     }
1368 
isUsingNonTerrestrialNetwork()1369     private boolean isUsingNonTerrestrialNetwork() {
1370         if (mPhone.getServiceState() == null) {
1371             return false;
1372         }
1373         return mPhone.getServiceState().isUsingNonTerrestrialNetwork();
1374     }
1375 
log(String msg)1376     private static void log(String msg) {
1377         if (DBG) Rlog.d(TAG, msg);
1378     }
1379 
loge(String msg)1380     private static void loge(String msg) {
1381         Rlog.e(TAG, msg);
1382     }
1383 
1384     /** Print to both Radio log and LocalLog, used only for critical but non-sensitive msg. */
localLog(String msg)1385     private void localLog(String msg) {
1386         Rlog.d(TAG, msg);
1387         mLocalLog.log(TAG + ": " + msg);
1388     }
1389 }
1390