Merge "Enforce READ_PHONE_STATE for APIs involving call state" into sc-dev am: 3bf5cbb891

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13986047

Change-Id: Ie676bae0c3df82e4a51c6b3c3fc9b6e040e172ce
This commit is contained in:
Brad Ebinger
2021-03-29 21:04:26 +00:00
committed by Automerger Merge Worker
9 changed files with 122 additions and 20 deletions

View File

@@ -40284,6 +40284,7 @@ package android.telecom {
field public static final int DURATION_MEDIUM = 2; // 0x2 field public static final int DURATION_MEDIUM = 2; // 0x2
field public static final int DURATION_SHORT = 1; // 0x1 field public static final int DURATION_SHORT = 1; // 0x1
field public static final int DURATION_VERY_SHORT = 0; // 0x0 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_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_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
@@ -41890,7 +41891,7 @@ package android.telephony {
method @Deprecated public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo); 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 @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
method @Deprecated public void onCallForwardingIndicatorChanged(boolean); 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 onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
method @Deprecated public void onCellLocationChanged(android.telephony.CellLocation); method @Deprecated public void onCellLocationChanged(android.telephony.CellLocation);
method @Deprecated public void onDataActivity(int); method @Deprecated public void onDataActivity(int);
@@ -42436,7 +42437,7 @@ package android.telephony {
} }
public static interface TelephonyCallback.CallStateListener { 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 { public static interface TelephonyCallback.CarrierNetworkListener {
@@ -42526,7 +42527,8 @@ package android.telephony {
method public int getActiveModemCount(); method public int getActiveModemCount();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); 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 @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 public int getCardIdForDefaultEuicc();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
method public int getCarrierIdFromSimMccMnc(); method public int getCarrierIdFromSimMccMnc();

View File

@@ -10877,7 +10877,7 @@ package android.telecom {
method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts(); method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
method public int getAllPhoneAccountsCount(); method public int getAllPhoneAccountsCount();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean); 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 public android.telecom.PhoneAccountHandle getConnectionManager();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode(); 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); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle);

View File

@@ -703,6 +703,10 @@ public class PhoneStateListener {
* calling {@link TelephonyManager#getCallState()} from within this callback may return a * calling {@link TelephonyManager#getCallState()} from within this callback may return a
* different state than the callback reports. * 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 state call state
* @param phoneNumber call phone number. If application does not have * @param phoneNumber call phone number. If application does not have
* {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier * {@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 Use {@link TelephonyCallback.CallStateListener} instead.
*/ */
@Deprecated @Deprecated
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
public void onCallStateChanged(@CallState int state, String phoneNumber) { public void onCallStateChanged(@CallState int state, String phoneNumber) {
// default implementation empty // default implementation empty
} }

View File

@@ -752,6 +752,7 @@ public class TelephonyCallback {
* *
* @param state the current call state * @param state the current call state
*/ */
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public void onCallStateChanged(@Annotation.CallState int state); public void onCallStateChanged(@Annotation.CallState int state);
} }

View File

@@ -44,6 +44,7 @@ import android.os.Process;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
import android.telephony.Annotation; import android.telephony.Annotation;
import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState; import android.telephony.Annotation.SrvccState;
@@ -215,6 +216,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled( return Binder.withCleanCallingIdentity(() -> CompatChanges.isChangeEnabled(
TelephonyCallback.PHONE_STATE_LISTENER_LIMIT_CHANGE_ID, uid)); 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; 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)) { if (isPrecisePhoneStatePermissionRequired(events)) {
// check if calling app has either permission READ_PRECISE_PHONE_STATE // check if calling app has either permission READ_PRECISE_PHONE_STATE
// or with carrier privileges // or with carrier privileges

View File

@@ -25,6 +25,8 @@ import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -1004,6 +1006,17 @@ public class TelecomManager {
PRESENTATION_PAYPHONE}) PRESENTATION_PAYPHONE})
public @interface Presentation {} 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"; private static final String TAG = "TelecomManager";
@@ -1758,21 +1771,23 @@ public class TelecomManager {
* {@link TelephonyManager#CALL_STATE_OFFHOOK} * {@link TelephonyManager#CALL_STATE_OFFHOOK}
* {@link TelephonyManager#CALL_STATE_IDLE} * {@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. * 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 * @hide
*/ */
@RequiresPermission(anyOf = {READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PHONE_STATE}, conditional = true)
@SystemApi @SystemApi
public @CallState int getCallState() { public @CallState int getCallState() {
ITelecomService service = getTelecomService(); ITelecomService service = getTelecomService();
if (service != null) { if (service != null) {
try { try {
return service.getCallState(); return service.getCallStateUsingPackage(mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) { } catch (RemoteException e) {
Log.d(TAG, "RemoteException calling getCallState().", e); Log.d(TAG, "RemoteException calling getCallState().", e);
} }

View File

@@ -195,10 +195,17 @@ interface ITelecomService {
/** /**
* @see TelecomServiceImpl#getCallState * @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) @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
int getCallState(); int getCallState();
/**
* @see TelecomServiceImpl#getCallState
*/
int getCallStateUsingPackage(String callingPackage, String callingFeatureId);
/** /**
* @see TelecomServiceImpl#endCall * @see TelecomServiceImpl#endCall
*/ */

View File

@@ -5725,9 +5725,20 @@ public class TelephonyManager {
* Note: The call state returned via this method may differ from what is reported by * 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 * {@link PhoneStateListener#onCallStateChanged(int, String)}, as that callback only considers
* Telephony (mobile) calls. * 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. * @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() { public @CallState int getCallState() {
if (mContext != null) { if (mContext != null) {
TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
@@ -5738,20 +5749,49 @@ public class TelephonyManager {
return CALL_STATE_IDLE; 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. * Returns the Telephony call state for calls on a specific subscription.
* <p> * <p>
* Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()} * Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()}
* considers the state of calls from other {@link android.telecom.ConnectionService} * considers the state of calls from other {@link android.telecom.ConnectionService}
* implementations. * 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. * @param subId the subscription to check call state for.
* @hide * @hide
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
public @CallState int getCallState(int subId) { public @CallState int getCallState(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId); ITelephony telephony = getITelephony();
return getCallStateForSlot(phoneId); if (telephony == null) {
return CALL_STATE_IDLE;
}
try {
return telephony.getCallStateForSubscription(subId, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
return CALL_STATE_IDLE;
}
} }
/** /**
@@ -5768,22 +5808,28 @@ public class TelephonyManager {
* Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()} * Note: This method considers ONLY telephony/mobile calls, where {@link #getCallState()}
* considers the state of calls from other {@link android.telecom.ConnectionService} * considers the state of calls from other {@link android.telecom.ConnectionService}
* implementations. * 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. * @param slotIndex the SIM slot index to check call state for.
* @hide * @hide
*/ */
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
public @CallState int getCallStateForSlot(int slotIndex) { public @CallState int getCallStateForSlot(int slotIndex) {
try { try {
int[] subId = SubscriptionManager.getSubId(slotIndex);
ITelephony telephony = getITelephony(); ITelephony telephony = getITelephony();
if (telephony == null) if (telephony == null || subId == null || subId.length == 0) {
return CALL_STATE_IDLE; 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. // the phone process is restarting.
return CALL_STATE_IDLE; return CALL_STATE_IDLE;
} catch (NullPointerException ex) {
// the phone process is restarting.
return CALL_STATE_IDLE;
} }
} }

View File

@@ -298,9 +298,9 @@ interface ITelephony {
int getCallState(); 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. * Replaced by getDataActivityForSubId.