Enforce READ_PHONE_STATE for APIs involving call state
For API version 31+, ensure that READ_PHONE_STATE is checked on APIs that retrieve/notify the call state of the device. Bug: 157233955 Test: atest CtsTelecomTestCases2 CtsTelephony2TestCases Change-Id: I9f8674a3075d3e0f75ee4f41eefce328c0fa6b91
This commit is contained in:
@@ -40190,6 +40190,7 @@ package android.telecom {
|
||||
field public static final int DURATION_MEDIUM = 2; // 0x2
|
||||
field public static final int DURATION_SHORT = 1; // 0x1
|
||||
field public static final int DURATION_VERY_SHORT = 0; // 0x0
|
||||
field public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L; // 0x95f3323L
|
||||
field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
|
||||
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
|
||||
field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
|
||||
@@ -41796,7 +41797,7 @@ package android.telephony {
|
||||
method @Deprecated public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
|
||||
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
|
||||
method @Deprecated public void onCallForwardingIndicatorChanged(boolean);
|
||||
method @Deprecated public void onCallStateChanged(int, String);
|
||||
method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public void onCallStateChanged(int, String);
|
||||
method @Deprecated public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
|
||||
method @Deprecated public void onCellLocationChanged(android.telephony.CellLocation);
|
||||
method @Deprecated public void onDataActivity(int);
|
||||
@@ -42342,7 +42343,7 @@ package android.telephony {
|
||||
}
|
||||
|
||||
public static interface TelephonyCallback.CallStateListener {
|
||||
method public void onCallStateChanged(int);
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallStateChanged(int);
|
||||
}
|
||||
|
||||
public static interface TelephonyCallback.CarrierNetworkListener {
|
||||
@@ -42432,7 +42433,8 @@ package android.telephony {
|
||||
method public int getActiveModemCount();
|
||||
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
|
||||
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus();
|
||||
method public int getCallState();
|
||||
method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public int getCallState();
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCallStateForSubscription();
|
||||
method public int getCardIdForDefaultEuicc();
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
|
||||
method public int getCarrierIdFromSimMccMnc();
|
||||
|
||||
@@ -10880,7 +10880,7 @@ package android.telecom {
|
||||
method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
|
||||
method public int getAllPhoneAccountsCount();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
|
||||
method public int getCallState();
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}, conditional=true) public int getCallState();
|
||||
method public android.telecom.PhoneAccountHandle getConnectionManager();
|
||||
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
|
||||
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle);
|
||||
|
||||
@@ -703,6 +703,10 @@ public class PhoneStateListener {
|
||||
* calling {@link TelephonyManager#getCallState()} from within this callback may return a
|
||||
* different state than the callback reports.
|
||||
*
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
|
||||
* targeting API level 31+.
|
||||
*
|
||||
* @param state call state
|
||||
* @param phoneNumber call phone number. If application does not have
|
||||
* {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier
|
||||
@@ -712,6 +716,7 @@ public class PhoneStateListener {
|
||||
* @deprecated Use {@link TelephonyCallback.CallStateListener} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
|
||||
public void onCallStateChanged(@CallState int state, String phoneNumber) {
|
||||
// default implementation empty
|
||||
}
|
||||
|
||||
@@ -752,6 +752,7 @@ public class TelephonyCallback {
|
||||
*
|
||||
* @param state the current call state
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
|
||||
public void onCallStateChanged(@Annotation.CallState int state);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.Annotation;
|
||||
import android.telephony.Annotation.RadioPowerState;
|
||||
import android.telephony.Annotation.SrvccState;
|
||||
@@ -215,6 +216,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
|
||||
TelephonyCallback.PHONE_STATE_LISTENER_LIMIT_CHANGE_ID, uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link TelecomManager#ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION} for more
|
||||
* information.
|
||||
* @noinspection ConstantConditions
|
||||
*/
|
||||
public boolean isCallStateReadPhoneStateEnforcedInPlatformCompat(String packageName,
|
||||
UserHandle userHandle) {
|
||||
return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
|
||||
TelecomManager.ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION, packageName,
|
||||
userHandle));
|
||||
}
|
||||
}
|
||||
|
||||
private final Context mContext;
|
||||
@@ -2947,6 +2960,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// Only check READ_PHONE_STATE for CALL_STATE_CHANGED for API 31+.
|
||||
if (mConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(callingPackage,
|
||||
Binder.getCallingUserHandle())) {
|
||||
if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)
|
||||
|| events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) {
|
||||
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
|
||||
mContext, subId, callingPackage, callingFeatureId, message)) {
|
||||
throw new SecurityException("CALL_STATE_CHANGED event requires "
|
||||
+ "READ_PHONE_STATE");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isPrecisePhoneStatePermissionRequired(events)) {
|
||||
// check if calling app has either permission READ_PRECISE_PHONE_STATE
|
||||
// or with carrier privileges
|
||||
|
||||
@@ -25,6 +25,8 @@ import android.annotation.SuppressAutoDoc;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -1004,6 +1006,17 @@ public class TelecomManager {
|
||||
PRESENTATION_PAYPHONE})
|
||||
public @interface Presentation {}
|
||||
|
||||
|
||||
/**
|
||||
* Enable READ_PHONE_STATE protection on APIs querying and notifying call state, such as
|
||||
* {@code TelecomManager#getCallState}, {@link TelephonyManager#getCallStateForSubscription()},
|
||||
* and {@link android.telephony.TelephonyCallback.CallStateListener}.
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
|
||||
// this magic number is a bug ID
|
||||
public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L;
|
||||
|
||||
private static final String TAG = "TelecomManager";
|
||||
|
||||
|
||||
@@ -1758,21 +1771,23 @@ public class TelecomManager {
|
||||
* {@link TelephonyManager#CALL_STATE_OFFHOOK}
|
||||
* {@link TelephonyManager#CALL_STATE_IDLE}
|
||||
*
|
||||
* Note that this API does not require the
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE} permission. This is intentional, to
|
||||
* preserve the behavior of {@link TelephonyManager#getCallState()}, which also did not require
|
||||
* the permission.
|
||||
*
|
||||
* Takes into consideration both managed and self-managed calls.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
|
||||
* targeting API level 31+.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(anyOf = {READ_PRIVILEGED_PHONE_STATE,
|
||||
android.Manifest.permission.READ_PHONE_STATE}, conditional = true)
|
||||
@SystemApi
|
||||
public @CallState int getCallState() {
|
||||
ITelecomService service = getTelecomService();
|
||||
if (service != null) {
|
||||
try {
|
||||
return service.getCallState();
|
||||
return service.getCallStateUsingPackage(mContext.getPackageName(),
|
||||
mContext.getAttributionTag());
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "RemoteException calling getCallState().", e);
|
||||
}
|
||||
|
||||
@@ -195,10 +195,17 @@ interface ITelecomService {
|
||||
|
||||
/**
|
||||
* @see TelecomServiceImpl#getCallState
|
||||
* Note: only kept around to not break app compat, however this will throw a SecurityException
|
||||
* on API 31+.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||
int getCallState();
|
||||
|
||||
/**
|
||||
* @see TelecomServiceImpl#getCallState
|
||||
*/
|
||||
int getCallStateUsingPackage(String callingPackage, String callingFeatureId);
|
||||
|
||||
/**
|
||||
* @see TelecomServiceImpl#endCall
|
||||
*/
|
||||
|
||||
@@ -5702,9 +5702,20 @@ public class TelephonyManager {
|
||||
* Note: The call state returned via this method may differ from what is reported by
|
||||
* {@link PhoneStateListener#onCallStateChanged(int, String)}, as that callback only considers
|
||||
* Telephony (mobile) calls.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
|
||||
* targeting API level 31+.
|
||||
*
|
||||
* @return the current call state.
|
||||
* @deprecated Use {@link #getCallStateForSubscription} to retrieve the call state for a
|
||||
* specific telephony subscription (which allows carrier privileged apps),
|
||||
* {@link TelephonyCallback.CallStateListener} for real-time call state updates, or
|
||||
* {@link TelecomManager#isInCall()}, which supplies an aggregate "in call" state for the entire
|
||||
* device.
|
||||
*/
|
||||
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
|
||||
@Deprecated
|
||||
public @CallState int getCallState() {
|
||||
if (mContext != null) {
|
||||
TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
|
||||
@@ -5715,20 +5726,49 @@ public class TelephonyManager {
|
||||
return CALL_STATE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the call state for a specific subscription that was specified when this
|
||||
* TelephonyManager instance was created.
|
||||
* <p>Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or that the calling
|
||||
* application has carrier privileges (see {@link #hasCarrierPrivileges}).
|
||||
* @see TelephonyManager#createForSubscriptionId(int)
|
||||
* @see TelephonyManager#createForPhoneAccountHandle(PhoneAccountHandle)
|
||||
* @return The call state of the subscription associated with this TelephonyManager instance.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
|
||||
public @CallState int getCallStateForSubscription() {
|
||||
return getCallState(getSubId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Telephony call state for calls on a specific subscription.
|
||||
* <p>
|
||||
* Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()}
|
||||
* considers the state of calls from other {@link android.telecom.ConnectionService}
|
||||
* implementations.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
|
||||
* targeting API level 31+ or that the calling application has carrier privileges
|
||||
* (see {@link #hasCarrierPrivileges()}).
|
||||
*
|
||||
* @param subId the subscription to check call state for.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
|
||||
public @CallState int getCallState(int subId) {
|
||||
int phoneId = SubscriptionManager.getPhoneId(subId);
|
||||
return getCallStateForSlot(phoneId);
|
||||
ITelephony telephony = getITelephony();
|
||||
if (telephony == null) {
|
||||
return CALL_STATE_IDLE;
|
||||
}
|
||||
try {
|
||||
return telephony.getCallStateForSubscription(subId, mContext.getPackageName(),
|
||||
mContext.getAttributionTag());
|
||||
} catch (RemoteException e) {
|
||||
return CALL_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5745,22 +5785,28 @@ public class TelephonyManager {
|
||||
* Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()}
|
||||
* considers the state of calls from other {@link android.telecom.ConnectionService}
|
||||
* implementations.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} for applications
|
||||
* targeting API level 31+ or that the calling application has carrier privileges
|
||||
* (see {@link #hasCarrierPrivileges()}).
|
||||
*
|
||||
* @param slotIndex the SIM slot index to check call state for.
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
|
||||
public @CallState int getCallStateForSlot(int slotIndex) {
|
||||
try {
|
||||
int[] subId = SubscriptionManager.getSubId(slotIndex);
|
||||
ITelephony telephony = getITelephony();
|
||||
if (telephony == null)
|
||||
if (telephony == null || subId == null || subId.length == 0) {
|
||||
return CALL_STATE_IDLE;
|
||||
return telephony.getCallStateForSlot(slotIndex);
|
||||
} catch (RemoteException ex) {
|
||||
}
|
||||
return telephony.getCallStateForSubscription(subId[0], mContext.getPackageName(),
|
||||
mContext.getAttributionTag());
|
||||
} catch (RemoteException | NullPointerException ex) {
|
||||
// the phone process is restarting.
|
||||
return CALL_STATE_IDLE;
|
||||
} catch (NullPointerException ex) {
|
||||
// the phone process is restarting.
|
||||
return CALL_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -298,9 +298,9 @@ interface ITelephony {
|
||||
int getCallState();
|
||||
|
||||
/**
|
||||
* Returns the call state for a slot.
|
||||
* Returns the call state for a specific subscriiption.
|
||||
*/
|
||||
int getCallStateForSlot(int slotIndex);
|
||||
int getCallStateForSubscription(int subId, String callingPackage, String featureId);
|
||||
|
||||
/**
|
||||
* Replaced by getDataActivityForSubId.
|
||||
|
||||
Reference in New Issue
Block a user