Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65fdd958 authored by Rambo Wang's avatar Rambo Wang
Browse files

Implement main functions to consolidate signal strength request

Bug: 164432835
Test: atest com.android.internal.telephony.ServiceStateTrackerTest
Change-Id: I158d6388b04b64f4b28305b258e79519f3a51d3f
parent 2fa15e91
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -398,7 +398,7 @@ public class DeviceStateMonitor extends Handler {
     *
     * @return True if the response update should be enabled.
     */
    private boolean shouldEnableHighPowerConsumptionIndications() {
    public boolean shouldEnableHighPowerConsumptionIndications() {
        // We should enable indications reports if one of the following condition is true.
        // 1. The device is charging.
        // 2. When the screen is on.
@@ -477,6 +477,7 @@ public class DeviceStateMonitor extends Handler {
     */
    private void onUpdateDeviceState(int eventType, boolean state) {
        final boolean shouldEnableBarringInfoReportsOld = shouldEnableBarringInfoReports();
        final boolean wasHighPowerEnabled = shouldEnableHighPowerConsumptionIndications();
        switch (eventType) {
            case EVENT_SCREEN_STATE_CHANGED:
                if (mIsScreenOn == state) return;
@@ -512,6 +513,11 @@ public class DeviceStateMonitor extends Handler {
                return;
        }

        final boolean isHighPowerEnabled = shouldEnableHighPowerConsumptionIndications();
        if (wasHighPowerEnabled != isHighPowerEnabled) {
            mPhone.notifyDeviceIdleStateChanged(!isHighPowerEnabled /*isIdle*/);
        }

        final int newCellInfoMinInterval = computeCellInfoMinInterval();
        if (mCellInfoMinInterval != newCellInfoMinInterval) {
            mCellInfoMinInterval = newCellInfoMinInterval;
+6 −1
Original line number Diff line number Diff line
@@ -4054,13 +4054,18 @@ public class GsmCdmaPhone extends Phone {
    @Override
    public void setSignalStrengthReportingCriteria(
            int signalStrengthMeasure, int[] thresholds, int ran, boolean isEnabled) {
        int[] consolidatedThresholds = mSST.getConsolidatedSignalThresholds(
                ran,
                signalStrengthMeasure,
                mSST.shouldHonorSystemThresholds() ? thresholds : new int[]{},
                REPORTING_HYSTERESIS_DB);
        mCi.setSignalStrengthReportingCriteria(
                new SignalThresholdInfo.Builder()
                        .setRadioAccessNetworkType(ran)
                        .setSignalMeasurementType(signalStrengthMeasure)
                        .setHysteresisMs(REPORTING_HYSTERESIS_MILLIS)
                        .setHysteresisDb(REPORTING_HYSTERESIS_DB)
                        .setThresholds(thresholds)
                        .setThresholdsUnlimited(consolidatedThresholds)
                        .setIsEnabled(isEnabled)
                        .build(),
                ran, null);
+30 −0
Original line number Diff line number Diff line
@@ -4599,6 +4599,36 @@ public abstract class Phone extends Handler implements PhoneInternalInterface {
        return false;
    }

    /**
     * Check if device is idle. Device is idle when it is not in high power consumption mode.
     *
     * @see DeviceStateMonitor#shouldEnableHighPowerConsumptionIndications()
     *
     * @return true if device is idle
     */
    public boolean isDeviceIdle() {
        DeviceStateMonitor dsm = getDeviceStateMonitor();
        if (dsm == null) {
            Rlog.e(LOG_TAG, "isDeviceIdle: DeviceStateMonitor is null");
            return false;
        }
        return !dsm.shouldEnableHighPowerConsumptionIndications();
    }

    /**
     * Get notified when device idleness state has changed
     *
     * @param isIdle true if the new state is idle
     */
    public void notifyDeviceIdleStateChanged(boolean isIdle) {
        ServiceStateTracker sst = getServiceStateTracker();
        if (sst == null) {
            Rlog.e(LOG_TAG, "notifyDeviceIdleStateChanged: SST is null");
            return;
        }
        sst.onDeviceIdleStateChanged(isIdle);
    }

    /**
     * Returns a list of the equivalent home PLMNs (EF_EHPLMN) from the USIM app.
     *
+200 −0
Original line number Diff line number Diff line
@@ -44,11 +44,13 @@ import android.os.AsyncResult;
import android.os.BaseBundle;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.TimestampedValue;
@@ -77,6 +79,7 @@ import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
import android.telephony.ServiceState.RilRadioTechnology;
import android.telephony.SignalStrength;
import android.telephony.SignalStrengthUpdateRequest;
import android.telephony.SignalThresholdInfo;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -125,9 +128,11 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -293,6 +298,9 @@ public class ServiceStateTracker extends Handler {
    protected static final int EVENT_CELL_LOCATION_RESPONSE            = 56;
    protected static final int EVENT_CARRIER_CONFIG_CHANGED            = 57;
    private static final int EVENT_POLL_STATE_REQUEST                  = 58;
    private static final int EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST = 59;
    private static final int EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST = 60;
    private static final int EVENT_ON_DEVICE_IDLE_STATE_CHANGED        = 61;

    /**
     * The current service state.
@@ -643,6 +651,9 @@ public class ServiceStateTracker extends Handler {
    private final Object mLteRsrpBoostLock = new Object();
    private static final int INVALID_LTE_EARFCN = -1;

    // @GuardedBy("mSignalRequestRecords")
    private final List<SignalRequestRecord> mSignalRequestRecords = new ArrayList<>();

    public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
        mNitzState = TelephonyComponentFactory.getInstance()
                .inject(NitzStateMachine.class.getName())
@@ -1750,6 +1761,76 @@ public class ServiceStateTracker extends Handler {
                pollStateInternal(false);
                break;

            case EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST: {
                Pair<SignalRequestRecord, Message> pair =
                        (Pair<SignalRequestRecord, Message>) msg.obj;
                SignalRequestRecord record = pair.first;
                Message onCompleted = pair.second;
                AsyncResult ret = AsyncResult.forMessage(onCompleted);

                // TODO(b/177956310): Check subId to filter out old request until a better solution
                boolean dupRequest = mSignalRequestRecords.stream().anyMatch(
                        srr -> srr.mCallingUid == record.mCallingUid
                                && srr.mSubId == record.mSubId);
                if (dupRequest) {
                    ret.exception = new IllegalStateException(
                            "setSignalStrengthUpdateRequest called again with same subId");
                    onCompleted.sendToTarget();
                    break;
                }

                try {
                    record.mRequest.getLiveToken().linkToDeath(record, 0);
                } catch (RemoteException | NullPointerException ex) {
                    ret.exception = new IllegalStateException(
                            "Signal request client is already dead.");
                    onCompleted.sendToTarget();
                    break;
                }

                synchronized (mSignalRequestRecords) {
                    mSignalRequestRecords.add(record);
                }

                updateAlwaysReportSignalStrength();
                updateReportingCriteria(getCarrierConfig());

                onCompleted.sendToTarget();
                break;
            }

            case EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST: {
                Pair<SignalRequestRecord, Message> pair =
                        (Pair<SignalRequestRecord, Message>) msg.obj;
                SignalRequestRecord record = pair.first;
                Message onCompleted = pair.second;

                synchronized (mSignalRequestRecords) {
                    // for loop with removal may cause ConcurrentModificationException
                    Iterator<SignalRequestRecord> it = mSignalRequestRecords.iterator();
                    while (it.hasNext()) {
                        SignalRequestRecord srr = it.next();
                        if (srr.mRequest.getLiveToken().equals(record.mRequest.getLiveToken())) {
                            it.remove();
                        }
                    }
                }

                updateAlwaysReportSignalStrength();
                updateReportingCriteria(getCarrierConfig());

                if (onCompleted != null) {
                    AsyncResult ret = AsyncResult.forMessage(onCompleted);
                    onCompleted.sendToTarget();
                }
                break;
            }

            case EVENT_ON_DEVICE_IDLE_STATE_CHANGED: {
                updateReportingCriteria(getCarrierConfig());
                break;
            }

            default:
                log("Unhandled message with number: " + msg.what);
                break;
@@ -5941,4 +6022,123 @@ public class ServiceStateTracker extends Handler {
        values.put(SERVICE_STATE, p.marshall());
        return values;
    }

    /**
     * Set a new request to update the signal strength thresholds.
     */
    public void setSignalStrengthUpdateRequest(int subId, int callingUid,
            SignalStrengthUpdateRequest request, @NonNull Message onCompleted) {
        SignalRequestRecord record = new SignalRequestRecord(subId, callingUid, request);
        sendMessage(obtainMessage(EVENT_SET_SIGNAL_STRENGTH_UPDATE_REQUEST,
                new Pair<SignalRequestRecord, Message>(record, onCompleted)));
    }

    /**
     * Clear the previously set request.
     */
    public void clearSignalStrengthUpdateRequest(int subId, int callingUid,
            SignalStrengthUpdateRequest request, @Nullable Message onCompleted) {
        SignalRequestRecord record = new SignalRequestRecord(subId, callingUid, request);
        sendMessage(obtainMessage(EVENT_CLEAR_SIGNAL_STRENGTH_UPDATE_REQUEST,
                new Pair<SignalRequestRecord, Message>(record, onCompleted)));
    }

    /**
     * Align all the qualified thresholds set from applications to the {@code systemThresholds}
     * and consolidate a new thresholds array, follow rules below:
     * 1. All threshold values (whose interval is guaranteed to be larger than hysteresis) in
     *    {@code systemThresholds} will keep as it.
     * 2. Any threshold from apps that has interval less than hysteresis from any threshold in
     *    {@code systemThresholds} will be removed.
     * 3. The target thresholds will be {@code systemThresholds} + all qualified thresholds from
     *    apps, sorted in ascending order.
     */
    int[] getConsolidatedSignalThresholds(int ran, int measurement,
            int[] systemThresholds, int hysteresis) {

        // TreeSet with comparator that will filter element with interval less than hysteresis
        // from any current element
        Set<Integer> target = new TreeSet<>((x, y) -> {
            if (y >= x - hysteresis && y <= x + hysteresis) {
                return 0;
            }
            return Integer.compare(x, y);
        });

        for (int systemThreshold : systemThresholds) {
            target.add(systemThreshold);
        }

        final boolean isDeviceIdle = mPhone.isDeviceIdle();
        final int curSubId = mPhone.getSubId();
        synchronized (mSignalRequestRecords) {
            // The total number of record is small (10~15 tops). With each request has at most 5
            // SignalThresholdInfo which has at most 8 thresholds arrays. So the nested loop should
            // not be a concern here.
            for (SignalRequestRecord record : mSignalRequestRecords) {
                if (curSubId != record.mSubId
                        || (isDeviceIdle && !record.mRequest.isReportingRequestedWhileIdle())) {
                    continue;
                }
                for (SignalThresholdInfo info : record.mRequest.getSignalThresholdInfos()) {
                    if (ran == info.getRadioAccessNetworkType()
                            && measurement == info.getSignalMeasurementType()) {
                        for (int appThreshold : info.getThresholds()) {
                            target.add(appThreshold);
                        }
                    }
                }
            }
        }

        int[] targetArray = new int[target.size()];
        int i = 0;
        for (int element : target) {
            targetArray[i++] = element;
        }
        return targetArray;
    }

    boolean shouldHonorSystemThresholds() {
        if (!mPhone.isDeviceIdle()) {
            return true;
        }

        final int curSubId = mPhone.getSubId();
        return mSignalRequestRecords.stream().anyMatch(
                srr -> curSubId == srr.mSubId
                        && srr.mRequest.isSystemThresholdReportingRequestedWhileIdle());
    }

    void onDeviceIdleStateChanged(boolean isDeviceIdle) {
        sendMessage(obtainMessage(EVENT_ON_DEVICE_IDLE_STATE_CHANGED, isDeviceIdle));
    }

    private class SignalRequestRecord implements IBinder.DeathRecipient {
        final int mSubId; // subId the request originally applied to
        final int mCallingUid;
        final SignalStrengthUpdateRequest mRequest;

        SignalRequestRecord(int subId, int uid, SignalStrengthUpdateRequest request) {
            this.mCallingUid = uid;
            this.mSubId = subId;
            this.mRequest = request;
        }

        @Override
        public void binderDied() {
            clearSignalStrengthUpdateRequest(mSubId, mCallingUid, mRequest, null /*onCompleted*/);
        }
    }

    private void updateAlwaysReportSignalStrength() {
        final int curSubId = mPhone.getSubId();
        boolean alwaysReport = mSignalRequestRecords.stream().anyMatch(
                srr -> srr.mSubId == curSubId && (srr.mRequest.isReportingRequestedWhileIdle()
                        || srr.mRequest.isSystemThresholdReportingRequestedWhileIdle()));

        // TODO(b/177924721): TM#setAlwaysReportSignalStrength will be removed and we will not
        // worry about unset flag which was set by other client.
        mPhone.setAlwaysReportSignalStrength(alwaysReport);
    }
}