Merge "Implement main functions to consolidate signal strength request"
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index 94de555..204b7d6 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -398,7 +398,7 @@
*
* @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 @@
*/
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 @@
return;
}
+ final boolean isHighPowerEnabled = shouldEnableHighPowerConsumptionIndications();
+ if (wasHighPowerEnabled != isHighPowerEnabled) {
+ mPhone.notifyDeviceIdleStateChanged(!isHighPowerEnabled /*isIdle*/);
+ }
+
final int newCellInfoMinInterval = computeCellInfoMinInterval();
if (mCellInfoMinInterval != newCellInfoMinInterval) {
mCellInfoMinInterval = newCellInfoMinInterval;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 812a0c6..c983c1f 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -4054,13 +4054,18 @@
@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);
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 7d64a46..1948ac9 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -4600,6 +4600,36 @@
}
/**
+ * 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.
*
* @return A list of equivalent home PLMNs. Returns an empty list if EF_EHPLMN is empty or
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index ce37488..66cc005 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -44,11 +44,13 @@
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.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.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 @@
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 @@
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())
@@ -1752,6 +1763,76 @@
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;
@@ -5953,4 +6034,123 @@
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);
+ }
}