Add new APIs for owner groups to vote on radio power state

Bug: 228777724
Design doc: go/voting-radio-power-state
Test: Run the following tests
 - atest android.telephony.cts.TelephonyManagerTest
 - atest com.android.internal.telephony.ServiceStateTrackerTest
 - atest com.android.internal.telephony.data.DataNetworkControllerTest
 - atest com.android.internal.telephony.dataconnection.DcTrackerTest
 - atest com.android.internal.telephony.GsmCdmaPhoneTest
Change-Id: I4d49de3e056be62897a7472acc1c68c2a9932c27

Change-Id: I15750f49573d4213970b6b5228d5180c775f8536
This commit is contained in:
Thomas Nguyen
2022-07-15 18:15:02 +00:00
parent c59f56b558
commit 437bd386c7
3 changed files with 239 additions and 23 deletions

View File

@@ -13398,6 +13398,7 @@ package android.telephony {
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int checkCarrierPrivilegesForPackage(String);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int checkCarrierPrivilegesForPackageAnyPhone(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearRadioPowerOffForReason(int);
method public void dial(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
@@ -13443,6 +13444,7 @@ package android.telephony {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.PhoneCapability getPhoneCapability();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Set<java.lang.Integer> getRadioPowerOffReasons();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
method public int getSimApplicationState();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimApplicationState(int);
@@ -13497,6 +13499,7 @@ package android.telephony {
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestRadioPowerOffForReason(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
@@ -13521,9 +13524,9 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setNrDualConnectivityState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
@@ -13605,6 +13608,10 @@ package android.telephony {
field public static final int PREPARE_UNATTENDED_REBOOT_SUCCESS = 0; // 0x0
field public static final int RADIO_POWER_OFF = 0; // 0x0
field public static final int RADIO_POWER_ON = 1; // 0x1
field public static final int RADIO_POWER_REASON_CARRIER = 2; // 0x2
field public static final int RADIO_POWER_REASON_NEARBY_DEVICE = 3; // 0x3
field public static final int RADIO_POWER_REASON_THERMAL = 1; // 0x1
field public static final int RADIO_POWER_REASON_USER = 0; // 0x0
field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2
field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1

View File

@@ -140,6 +140,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -234,6 +235,54 @@ public class TelephonyManager {
public static final int NETWORK_SELECTION_MODE_AUTO = 1;
public static final int NETWORK_SELECTION_MODE_MANUAL = 2;
/**
* Reasons for Radio being powered off.
*
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"RADIO_POWER_REASON_"},
value = {
RADIO_POWER_REASON_USER,
RADIO_POWER_REASON_THERMAL,
RADIO_POWER_REASON_CARRIER,
RADIO_POWER_REASON_NEARBY_DEVICE})
public @interface RadioPowerReason {}
/**
* This reason is used when users want to turn off radio, e.g., users turn on airplane mode.
*
* @hide
*/
@SystemApi
public static final int RADIO_POWER_REASON_USER = 0;
/**
* This reason is used when radio needs to be turned off due to thermal.
*
* @hide
*/
@SystemApi
public static final int RADIO_POWER_REASON_THERMAL = 1;
/**
* This reason is used when carriers want to turn off radio. A privileged app can request to
* turn off radio via the system service
* {@link com.android.carrierdefaultapp.CaptivePortalLoginActivity}, which subsequently calls
* the system APIs {@link requestRadioPowerOffForReason} and
* {@link clearRadioPowerOffForReason}.
*
* @hide
*/
@SystemApi
public static final int RADIO_POWER_REASON_CARRIER = 2;
/**
* Used to reduce power on a battery-constrained device when Telephony services are available
* via a paired device which is nearby.
*
* @hide
*/
@SystemApi
public static final int RADIO_POWER_REASON_NEARBY_DEVICE = 3;
/** The otaspMode passed to PhoneStateListener#onOtaspChanged */
/** @hide */
static public final int OTASP_UNINITIALIZED = 0;
@@ -10506,34 +10555,155 @@ public class TelephonyManager {
}
}
/** @hide */
/**
* @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
* {@link clearRadioPowerOffForReason}.
*
* @hide
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public boolean setRadio(boolean turnOn) {
boolean result = true;
try {
ITelephony telephony = getITelephony();
if (telephony != null)
return telephony.setRadio(turnOn);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#setRadio", e);
if (turnOn) {
clearRadioPowerOffForReason(RADIO_POWER_REASON_USER);
} else {
requestRadioPowerOffForReason(RADIO_POWER_REASON_USER);
}
} catch (Exception e) {
String calledFunction =
turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason";
Log.e(TAG, "Error calling " + calledFunction, e);
result = false;
}
return false;
return result;
}
/** @hide */
/**
* @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
* {@link clearRadioPowerOffForReason}.
*
* @hide
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public boolean setRadioPower(boolean turnOn) {
boolean result = true;
try {
if (turnOn) {
clearRadioPowerOffForReason(RADIO_POWER_REASON_USER);
} else {
requestRadioPowerOffForReason(RADIO_POWER_REASON_USER);
}
} catch (Exception e) {
String calledFunction =
turnOn ? "clearRadioPowerOffForReason" : "requestRadioPowerOffForReason";
Log.e(TAG, "Error calling " + calledFunction, e);
result = false;
}
return result;
}
/**
* Vote on powering off the radio for a reason. The radio will be turned on only when there is
* no reason to power it off. When any of the voters want to power it off, it will be turned
* off. In case of emergency, the radio will be turned on even if there are some reasons for
* powering it off, and these radio off votes will be cleared.
* Multiple apps can vote for the same reason and the last vote will take effect. Each app is
* responsible for its vote. A powering-off vote of a reason will be maintained until it is
* cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
* is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
* sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
* check its vote.
*
* @param reason The reason for powering off radio.
* @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission.
* @throws IllegalStateException if the Telephony service is not currently available.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public void requestRadioPowerOffForReason(@RadioPowerReason int reason) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
return telephony.setRadioPower(turnOn);
if (telephony != null) {
if (!telephony.requestRadioPowerOffForReason(getSubId(), reason)) {
throw new IllegalStateException("Telephony service is not available.");
}
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#setRadioPower", e);
Log.e(TAG, "Error calling ITelephony#requestRadioPowerOffForReason", e);
e.rethrowAsRuntimeException();
}
return false;
}
/**
* Remove the vote on powering off the radio for a reason, as requested by
* {@link requestRadioPowerOffForReason}.
*
* @param reason The reason for powering off radio.
* @throws SecurityException if the caller does not have MODIFY_PHONE_STATE permission.
* @throws IllegalStateException if the Telephony service is not currently available.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public void clearRadioPowerOffForReason(@RadioPowerReason int reason) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
if (!telephony.clearRadioPowerOffForReason(getSubId(), reason)) {
throw new IllegalStateException("Telephony service is not available.");
}
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#clearRadioPowerOffForReason", e);
e.rethrowAsRuntimeException();
}
}
/**
* Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
* If the reason set is empty, the radio is on in all cases.
*
* @return Set of reasons for powering off radio.
* @throws SecurityException if the caller does not have READ_PRIVILEGED_PHONE_STATE permission.
* @throws IllegalStateException if the Telephony service is not currently available.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
@NonNull
public Set<Integer> getRadioPowerOffReasons() {
Set<Integer> result = new HashSet<>();
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
result.addAll(telephony.getRadioPowerOffReasons(getSubId(),
mContext.getOpPackageName(), mContext.getAttributionTag()));
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getRadioPowerOffReasons", e);
e.rethrowAsRuntimeException();
}
return result;
}
/**
@@ -13037,20 +13207,21 @@ public class TelephonyManager {
*
* @param enabled control enable or disable radio.
* @see #resetAllCarrierActions()
*
* @deprecated - use the APIs {@link requestRadioPowerOffForReason} and
* {@link clearRadioPowerOffForReason}.
*
* @hide
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
public void setRadioEnabled(boolean enabled) {
try {
ITelephony service = getITelephony();
if (service != null) {
service.carrierActionSetRadioEnabled(
getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e);
if (enabled) {
clearRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER);
} else {
requestRadioPowerOffForReason(RADIO_POWER_REASON_CARRIER);
}
}

View File

@@ -243,6 +243,44 @@ interface ITelephony {
*/
boolean setRadioPower(boolean turnOn);
/**
* Vote on powering off the radio for a reason. The radio will be turned on only when there is
* no reason to power it off. When any of the voters want to power it off, it will be turned
* off. In case of emergency, the radio will be turned on even if there are some reasons for
* powering it off, and these radio off votes will be cleared.
* Multiple apps can vote for the same reason and the last vote will take effect. Each app is
* responsible for its vote. A powering-off vote of a reason will be maintained until it is
* cleared by calling {@link clearRadioPowerOffForReason} for that reason, or an emergency call
* is made, or the device is rebooted. When an app comes backup from a crash, it needs to make
* sure if its vote is as expected. An app can use the API {@link getRadioPowerOffReasons} to
* check its vote.
*
* @param subId The subscription ID.
* @param reason The reason for powering off radio.
* @return true on success and false on failure.
*/
boolean requestRadioPowerOffForReason(int subId, int reason);
/**
* Remove the vote on powering off the radio for a reasonas, requested by
* {@link requestRadioPowerOffForReason}.
*
* @param subId The subscription ID.
* @param reason The reason for powering off radio.
* @return true on success and false on failure.
*/
boolean clearRadioPowerOffForReason(int subId, int reason);
/**
* Get reasons for powering off radio, as requested by {@link requestRadioPowerOffForReason}.
*
* @param subId The subscription ID.
* @param callingPackage The package making the call.
* @param callingFeatureId The feature in the package.
* @return List of reasons for powering off radio.
*/
List getRadioPowerOffReasons(int subId, String callingPackage, String callingFeatureId);
/**
* This method has been removed due to security and stability issues.
*/