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