Routes thermalMitigationRequest to proper HAL APIs.
go/telephony-thermal-mitigation
Track whether an emergency call is pending for phone.
Necessary to know when thermal can turn off radio.
Bug: 158872959
Test: make
Change-Id: Iebe57e93d19486a1f3dc5e69abe326cc5d09e7fd
Merged-In: Iebe57e93d19486a1f3dc5e69abe326cc5d09e7fd
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 4473aaa..2834845 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -64,6 +64,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.ThermalMitigationResult;
import android.telephony.CallForwardingInfo;
import android.telephony.CarrierBandwidth;
import android.telephony.CarrierConfigManager;
@@ -75,6 +76,7 @@
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoWcdma;
import android.telephony.ClientRequestStats;
+import android.telephony.DataThrottlingRequest;
import android.telephony.ICellInfoCallback;
import android.telephony.IccOpenLogicalChannelResponse;
import android.telephony.LocationAccessPolicy;
@@ -93,6 +95,7 @@
import android.telephony.TelephonyHistogram;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyScanManager;
+import android.telephony.ThermalMitigationRequest;
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotInfo;
import android.telephony.UssdResponse;
@@ -179,6 +182,8 @@
import com.android.phone.vvm.RemoteVvmTaskManager;
import com.android.phone.vvm.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.VisualVoicemailSmsFilterConfig;
+import com.android.services.telephony.TelecomAccountRegistry;
+import com.android.services.telephony.TelephonyConnectionService;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -298,6 +303,8 @@
private static final int EVENT_GET_CDMA_SUBSCRIPTION_MODE_DONE = 96;
private static final int CMD_GET_SYSTEM_SELECTION_CHANNELS = 97;
private static final int EVENT_GET_SYSTEM_SELECTION_CHANNELS_DONE = 98;
+ private static final int CMD_SET_DATA_THROTTLING = 99;
+ private static final int EVENT_SET_DATA_THROTTLING_DONE = 100;
// Parameters of select command.
private static final int SELECT_COMMAND = 0xA4;
@@ -340,6 +347,8 @@
private static final int TYPE_ALLOCATION_CODE_LENGTH = 8;
private static final int MANUFACTURER_CODE_LENGTH = 8;
+ private static final int SET_DATA_THROTTLING_MODEM_THREW_INVALID_PARAMS = -1;
+
/**
* Experiment flag to enable erase modem config on reset network, default value is false
*/
@@ -1680,6 +1689,52 @@
getDefaultPhone().getContext().sendBroadcastAsUser(
intent, UserHandle.ALL, permission.USER_ACTIVITY);
break;
+
+ case CMD_SET_DATA_THROTTLING: {
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_SET_DATA_THROTTLING_DONE, request);
+ DataThrottlingRequest dataThrottlingRequest =
+ (DataThrottlingRequest) request.argument;
+ Phone phone = getPhoneFromRequest(request);
+ if (phone != null) {
+ phone.setDataThrottling(onCompleted,
+ request.workSource, dataThrottlingRequest.getDataThrottlingAction(),
+ dataThrottlingRequest.getCompletionDurationMillis());
+ } else {
+ loge("setDataThrottling: No phone object");
+ request.result =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ notifyRequester(request);
+ }
+
+ break;
+ }
+ case EVENT_SET_DATA_THROTTLING_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+
+ if (ar.exception == null) {
+ request.result = TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
+ } else if (ar.exception instanceof CommandException) {
+ loge("setDataThrottling: CommandException: " + ar.exception);
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+
+ if (error == CommandException.Error.RADIO_NOT_AVAILABLE) {
+ request.result = TelephonyManager
+ .THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ } else if (error == CommandException.Error.INVALID_ARGUMENTS) {
+ request.result = SET_DATA_THROTTLING_MODEM_THREW_INVALID_PARAMS;
+ } else {
+ request.result =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_ERROR;
+ }
+ } else {
+ request.result = TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_ERROR;
+ }
+ Log.w(LOG_TAG, "DataThrottlingResult = " + request.result);
+ notifyRequester(request);
+ break;
default:
Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
break;
@@ -9064,4 +9119,157 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ /**
+ * Attempts to set the radio power state for thermal reason. This does not guarantee that the
+ * requested radio power state will actually be set. See {@link
+ * PhoneInternalInterface#setRadioPowerForReason} for more details.
+ *
+ * @param subId the subscription ID of the phone requesting to set the radio power state.
+ * @param enable {@code true} if trying to turn radio on.
+ * @return {@code true} if phone setRadioPowerForReason was called. Otherwise, returns {@code
+ * false}.
+ */
+ private boolean setRadioPowerForThermal(int subId, boolean enable) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ phone.setRadioPowerForReason(enable, Phone.RADIO_POWER_REASON_THERMAL);
+ return true;
+ }
+ return false;
+ }
+
+ private int handleDataThrottlingRequest(int subId,
+ DataThrottlingRequest dataThrottlingRequest) {
+ // Ensure that radio is on. If not able to power on due to phone being unavailable, return
+ // THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE.
+ if (!setRadioPowerForThermal(subId, true)) {
+ return TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ }
+
+ setDataEnabledForReason(subId, TelephonyManager.DATA_ENABLED_REASON_THERMAL, true);
+
+ int thermalMitigationResult =
+ (int) sendRequest(CMD_SET_DATA_THROTTLING, dataThrottlingRequest, subId);
+ if (thermalMitigationResult == SET_DATA_THROTTLING_MODEM_THREW_INVALID_PARAMS) {
+ throw new IllegalArgumentException("modem returned INVALID_ARGUMENTS");
+ }
+ return thermalMitigationResult;
+ }
+
+ /**
+ * Thermal mitigation request to control functionalities at modem.
+ *
+ * @param subId the id of the subscription.
+ * @param thermalMitigationRequest holds all necessary information to be passed down to modem.
+ *
+ * @return thermalMitigationResult enum as defined in android.telephony.Annotation.
+ */
+ @Override
+ @ThermalMitigationResult
+ public int sendThermalMitigationRequest(
+ int subId,
+ ThermalMitigationRequest thermalMitigationRequest) throws IllegalArgumentException {
+ enforceModifyPermission();
+
+ WorkSource workSource = getWorkSource(Binder.getCallingUid());
+ final long identity = Binder.clearCallingIdentity();
+
+ int thermalMitigationResult = TelephonyManager.THERMAL_MITIGATION_RESULT_UNKNOWN_ERROR;
+ try {
+ int thermalMitigationAction = thermalMitigationRequest.getThermalMitigationAction();
+ switch (thermalMitigationAction) {
+ case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_DATA_THROTTLING:
+ thermalMitigationResult =
+ handleDataThrottlingRequest(subId,
+ thermalMitigationRequest.getDataThrottlingRequest());
+ break;
+ case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_VOICE_ONLY:
+ if (thermalMitigationRequest.getDataThrottlingRequest() != null) {
+ throw new IllegalArgumentException("dataThrottlingRequest must be null for "
+ + "ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_VOICE_ONLY");
+ }
+
+ // Ensure that radio is on. If not able to power on due to phone being
+ // unavailable, return THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE.
+ if (!setRadioPowerForThermal(subId, true)) {
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ break;
+ }
+
+ setDataEnabledForReason(subId, TelephonyManager.DATA_ENABLED_REASON_THERMAL,
+ false);
+ thermalMitigationResult = TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
+ break;
+ case ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_RADIO_OFF:
+ if (thermalMitigationRequest.getDataThrottlingRequest() != null) {
+ throw new IllegalArgumentException("dataThrottlingRequest must be null for"
+ + " ThermalMitigationRequest.THERMAL_MITIGATION_ACTION_RADIO_OFF");
+ }
+
+ TelecomAccountRegistry registry = TelecomAccountRegistry.getInstance(null);
+ if (registry != null) {
+ TelephonyConnectionService service =
+ registry.getTelephonyConnectionService();
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ break;
+ }
+
+ if (PhoneConstantConversions.convertCallState(phone.getState())
+ != TelephonyManager.CALL_STATE_IDLE
+ || phone.isInEmergencySmsMode() || phone.isInEcm()
+ || (service != null && service.isEmergencyCallPending())) {
+ String errorMessage = "Phone state is not valid. call state = "
+ + PhoneConstantConversions.convertCallState(phone.getState())
+ + " isInEmergencySmsMode = " + phone.isInEmergencySmsMode()
+ + " isInEmergencyCallbackMode = " + phone.isInEcm();
+ errorMessage += service == null
+ ? " TelephonyConnectionService is null"
+ : " isEmergencyCallPending = "
+ + service.isEmergencyCallPending();
+ Log.e(LOG_TAG, errorMessage);
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_INVALID_STATE;
+ break;
+ }
+ } else {
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ break;
+ }
+
+ // Turn radio off. If not able to power off due to phone being unavailable,
+ // return THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE.
+ if (!setRadioPowerForThermal(subId, false)) {
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_NOT_AVAILABLE;
+ break;
+ }
+ thermalMitigationResult =
+ TelephonyManager.THERMAL_MITIGATION_RESULT_SUCCESS;
+ break;
+ default:
+ throw new IllegalArgumentException("the requested thermalMitigationAction does "
+ + "not exist. Requested action: " + thermalMitigationAction);
+ }
+ } catch (IllegalArgumentException e) {
+ throw e;
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "thermalMitigationRequest. Exception e =" + e);
+ thermalMitigationResult = TelephonyManager.THERMAL_MITIGATION_RESULT_MODEM_ERROR;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ if (DBG) {
+ log("thermalMitigationRequest returning with thermalMitigationResult: "
+ + thermalMitigationResult);
+ }
+
+ return thermalMitigationResult;
+ }
}
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 0e7c8ed..8b5b64f 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -1134,7 +1134,7 @@
this.mTelephonyConnectionService = telephonyConnectionService;
}
- TelephonyConnectionService getTelephonyConnectionService() {
+ public TelephonyConnectionService getTelephonyConnectionService() {
return mTelephonyConnectionService;
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 322993a..0b1d56d 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -160,6 +160,9 @@
private EmergencyTonePlayer mEmergencyTonePlayer;
private HoldTracker mHoldTracker;
private boolean mIsTtyEnabled;
+ /** Set to true when there is an emergency call pending which will potential trigger a dial.
+ * This must be set to false when the call is dialed. */
+ private volatile boolean mIsEmergencyCallPending;
// Contains one TelephonyConnection that has placed a call and a memory of which Phones it has
// already tried to connect with. There should be only one TelephonyConnection trying to place a
@@ -800,6 +803,10 @@
if (mRadioOnHelper == null) {
mRadioOnHelper = new RadioOnHelper(this);
}
+
+ if (isEmergencyNumber) {
+ mIsEmergencyCallPending = true;
+ }
mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() {
@Override
public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
@@ -912,6 +919,14 @@
}
/**
+ * @return whether radio has recently been turned on for emergency call but hasn't actually
+ * dialed the call yet.
+ */
+ public boolean isEmergencyCallPending() {
+ return mIsEmergencyCallPending;
+ }
+
+ /**
* Whether the cellular radio is power off because the device is on Bluetooth.
*/
private boolean isRadioPowerDownOnBluetooth() {
@@ -936,6 +951,7 @@
for (Phone curPhone : mPhoneFactoryProxy.getPhones()) {
curPhone.setRadioPower(true, false, false, true);
}
+ mIsEmergencyCallPending = false;
}
return;
}
@@ -951,6 +967,7 @@
Log.i(this, "handleOnComplete - delayDialForDdsSwitch result = " + result);
adjustAndPlaceOutgoingConnection(phone, originalConnection, request,
numberToDial, handle, originalPhoneType, true);
+ mIsEmergencyCallPending = false;
}
});
}
@@ -961,6 +978,7 @@
mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.POWER_OFF,
"Failed to turn on radio."));
+ mIsEmergencyCallPending = false;
}
}