diff options
-rw-r--r-- | core/api/current.txt | 8 | ||||
-rw-r--r-- | core/api/system-current.txt | 2 | ||||
-rw-r--r-- | core/java/android/telephony/PhoneStateListener.java | 5 | ||||
-rw-r--r-- | core/java/android/telephony/TelephonyCallback.java | 1 | ||||
-rw-r--r-- | services/core/java/com/android/server/TelephonyRegistry.java | 26 | ||||
-rw-r--r-- | telecomm/java/android/telecom/TelecomManager.java | 27 | ||||
-rw-r--r-- | telecomm/java/com/android/internal/telecom/ITelecomService.aidl | 7 | ||||
-rw-r--r-- | telephony/java/android/telephony/TelephonyManager.java | 62 | ||||
-rw-r--r-- | telephony/java/com/android/internal/telephony/ITelephony.aidl | 4 |
9 files changed, 122 insertions, 20 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 935cf7067043..aaa4c2dfbfbf 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -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(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e8bdd41467d9..898780270f19 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -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); diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 1da7dc403d39..49065aaa2d23 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -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 } diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 18949cdbeeab..1ab6e0ffc34e 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -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); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 3ea44588e2da..b42a16db5814 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -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 diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 1677c8c1f08e..48867895bd5c 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -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); } diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 78283fa73514..18afde742abb 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -195,11 +195,18 @@ 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 */ boolean endCall(String callingPackage); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d2da51a1faca..eed42d914cf3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -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); @@ -5716,19 +5727,48 @@ public class TelephonyManager { } /** + * 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; } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 46752b7fe1ea..afc538d3bae3 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -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. |