diff options
Diffstat (limited to 'telephony/common')
5 files changed, 168 insertions, 25 deletions
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index 25b062f85d3e..85d59a216f25 100644 --- a/telephony/common/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -86,8 +86,9 @@ public final class LocationAccessPolicy { private String mCallingFeatureId; private int mCallingUid; private int mCallingPid; - private int mMinSdkVersionForCoarse = Integer.MAX_VALUE; - private int mMinSdkVersionForFine = Integer.MAX_VALUE; + private int mMinSdkVersionForCoarse = -1; + private int mMinSdkVersionForFine = -1; + private int mMinSdkVersionForEnforcement = -1; private boolean mLogAsInfo = false; private String mMethod; @@ -125,7 +126,14 @@ public final class LocationAccessPolicy { /** * Apps that target at least this sdk version will be checked for coarse location - * permission. Defaults to INT_MAX (which means don't check) + * permission. This method MUST be called before calling {@link #build()}. Otherwise, an + * {@link IllegalArgumentException} will be thrown. + * + * Additionally, if both the argument to this method and + * {@link #setMinSdkVersionForFine} are greater than {@link Build.VERSION_CODES#BASE}, + * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}. */ public Builder setMinSdkVersionForCoarse( int minSdkVersionForCoarse) { @@ -135,7 +143,14 @@ public final class LocationAccessPolicy { /** * Apps that target at least this sdk version will be checked for fine location - * permission. Defaults to INT_MAX (which means don't check) + * permission. This method MUST be called before calling {@link #build()}. + * Otherwise, an {@link IllegalArgumentException} will be thrown. + * + * Additionally, if both the argument to this method and + * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE}, + * you must call {@link #setMinSdkVersionForEnforcement} with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + * Otherwise, {@link #build} will throw an {@link IllegalArgumentException}. */ public Builder setMinSdkVersionForFine( int minSdkVersionForFine) { @@ -144,6 +159,17 @@ public final class LocationAccessPolicy { } /** + * If both the argument to {@link #setMinSdkVersionForFine} and + * {@link #setMinSdkVersionForCoarse} are greater than {@link Build.VERSION_CODES#BASE}, + * this method must be called with the min of the two to + * affirm that you do not want any location checks below a certain SDK version. + */ + public Builder setMinSdkVersionForEnforcement(int minSdkVersionForEnforcement) { + mMinSdkVersionForEnforcement = minSdkVersionForEnforcement; + return this; + } + + /** * Optional, for logging purposes only. */ public Builder setMethod(String method) { @@ -161,6 +187,26 @@ public final class LocationAccessPolicy { /** build LocationPermissionQuery */ public LocationPermissionQuery build() { + if (mMinSdkVersionForCoarse < 0 || mMinSdkVersionForFine < 0) { + throw new IllegalArgumentException("Must specify min sdk versions for" + + " enforcement for both coarse and fine permissions"); + } + if (mMinSdkVersionForFine > Build.VERSION_CODES.BASE + && mMinSdkVersionForCoarse > Build.VERSION_CODES.BASE) { + if (mMinSdkVersionForEnforcement != Math.min( + mMinSdkVersionForCoarse, mMinSdkVersionForFine)) { + throw new IllegalArgumentException("setMinSdkVersionForEnforcement must be" + + " called."); + } + } + + if (mMinSdkVersionForFine < mMinSdkVersionForCoarse) { + throw new IllegalArgumentException("Since fine location permission includes" + + " access to coarse location, the min sdk level for enforcement of" + + " the fine location permission must not be less than the min sdk" + + " level for enforcement of the coarse location permission."); + } + return new LocationPermissionQuery(mCallingPackage, mCallingFeatureId, mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, mLogAsInfo, mMethod); @@ -331,7 +377,7 @@ public final class LocationAccessPolicy { } private static boolean isCurrentProfile(@NonNull Context context, int uid) { - long token = Binder.clearCallingIdentity(); + final long token = Binder.clearCallingIdentity(); try { if (UserHandle.getUserHandleForUid(uid).getIdentifier() == ActivityManager.getCurrentUser()) { diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index d1412b772eef..8531b507a92f 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -25,7 +26,7 @@ import android.os.Build; import android.os.CarrierAssociatedAppEntry; import android.os.SystemConfigManager; import android.os.UserHandle; -import android.permission.PermissionManager; +import android.permission.LegacyPermissionManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -75,7 +76,7 @@ public final class CarrierAppUtils { * privileged apps may have changed. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - TelephonyManager telephonyManager, int userId, Context context) { + TelephonyManager telephonyManager, @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -102,7 +103,7 @@ public final class CarrierAppUtils { * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - int userId, Context context) { + @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -118,9 +119,9 @@ public final class CarrierAppUtils { systemCarrierAssociatedAppsDisabledUntilUsed, context); } - private static ContentResolver getContentResolverForUser(Context context, int userId) { - Context userContext = context.createContextAsUser(UserHandle.getUserHandleForUid(userId), - 0); + private static ContentResolver getContentResolverForUser(Context context, + @UserIdInt int userId) { + Context userContext = context.createContextAsUser(UserHandle.of(userId), 0); return userContext.getContentResolver(); } @@ -140,8 +141,8 @@ public final class CarrierAppUtils { Map<String, List<CarrierAssociatedAppEntry>> systemCarrierAssociatedAppsDisabledUntilUsed, Context context) { PackageManager packageManager = context.getPackageManager(); - PermissionManager permissionManager = - (PermissionManager) context.getSystemService(Context.PERMISSION_SERVICE); + LegacyPermissionManager permissionManager = (LegacyPermissionManager) + context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper( userId, systemCarrierAppsDisabledUntilUsed, context); if (candidates == null || candidates.isEmpty()) { @@ -153,7 +154,8 @@ public final class CarrierAppUtils { List<String> enabledCarrierPackages = new ArrayList<>(); int carrierAppsHandledSdk = - Settings.Secure.getInt(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0); + Settings.Secure.getIntForUser(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, + 0, contentResolver.getUserId()); if (DEBUG) { Log.i(TAG, "Last execution SDK: " + carrierAppsHandledSdk); } @@ -305,8 +307,8 @@ public final class CarrierAppUtils { // Mark the execution so we do not disable apps again on this SDK version. if (!hasRunEver || !hasRunForSdk) { - Settings.Secure.putInt(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, - Build.VERSION.SDK_INT); + Settings.Secure.putIntForUser(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, + Build.VERSION.SDK_INT, contentResolver.getUserId()); } if (!enabledCarrierPackages.isEmpty()) { diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index b8b60da019af..32533cbf97fb 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -17,8 +17,10 @@ package com.android.internal.telephony; import android.Manifest.permission; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -38,17 +40,20 @@ import android.os.Binder; import android.os.Build; import android.os.Process; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.telephony.PackageChangeReceiver; import android.telephony.TelephonyManager; import android.util.Log; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -86,6 +91,8 @@ public final class SmsApplication { private static SmsPackageMonitor sSmsPackageMonitor = null; + private static SmsRoleListener sSmsRoleListener = null; + public static class SmsApplicationData { /** * Name of this SMS app for display. @@ -525,7 +532,7 @@ public final class SmsApplication { } private static String getDefaultSmsPackage(Context context, int userId) { - return context.getSystemService(RoleManager.class).getDefaultSmsPackage(userId); + return context.getSystemService(RoleManager.class).getSmsRoleHolder(userId); } /** @@ -686,7 +693,7 @@ public final class SmsApplication { * {@link Intent#ACTION_DEFAULT_SMS_PACKAGE_CHANGED} * {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL} */ - public static void broadcastSmsAppChange(Context context, + private static void broadcastSmsAppChange(Context context, UserHandle userHandle, @Nullable String oldPackage, @Nullable String newPackage) { Collection<SmsApplicationData> apps = getApplicationCollection(context); @@ -845,9 +852,51 @@ public final class SmsApplication { } } + /** + * Tracks SMS role changes and sends broadcasts for default SMS app change. + */ + private static final class SmsRoleListener implements OnRoleHoldersChangedListener { + private final Context mContext; + private final RoleManager mRoleManager; + private final SparseArray<String> mSmsPackageNames = new SparseArray<>(); + + public SmsRoleListener(@NonNull Context context) { + mContext = context; + mRoleManager = context.getSystemService(RoleManager.class); + final List<UserHandle> users = context.getSystemService(UserManager.class) + .getUserHandles(true); + final int usersSize = users.size(); + for (int i = 0; i < usersSize; i++) { + final UserHandle user = users.get(i); + mSmsPackageNames.put(user.getIdentifier(), getSmsPackageName(user)); + } + mRoleManager.addOnRoleHoldersChangedListenerAsUser(context.getMainExecutor(), this, + UserHandle.ALL); + } + + @Override + public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { + if (!Objects.equals(roleName, RoleManager.ROLE_SMS)) { + return; + } + final int userId = user.getIdentifier(); + final String newSmsPackageName = getSmsPackageName(user); + broadcastSmsAppChange(mContext, user, mSmsPackageNames.get(userId), newSmsPackageName); + mSmsPackageNames.put(userId, newSmsPackageName); + } + + @Nullable + private String getSmsPackageName(@NonNull UserHandle user) { + final List<String> roleHolders = mRoleManager.getRoleHoldersAsUser( + RoleManager.ROLE_SMS, user); + return !roleHolders.isEmpty() ? roleHolders.get(0) : null; + } + } + public static void initSmsPackageMonitor(Context context) { sSmsPackageMonitor = new SmsPackageMonitor(context); sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL); + sSmsRoleListener = new SmsRoleListener(context); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 38fa9077f188..5e50bea05057 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -27,7 +27,7 @@ import android.os.Binder; import android.os.Build; import android.os.Process; import android.os.UserHandle; -import android.permission.PermissionManager; +import android.permission.LegacyPermissionManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -244,7 +244,9 @@ public final class TelephonyPermissions { * <ul> * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier - * access check, or the calling package has carrier privileges on any active subscription. + * access check, or the calling package has carrier privileges on any active + * subscription, or the calling package has the {@link + * Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} appop permission. * <li>throw SecurityException: if the caller does not meet any of the requirements and is * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission * or carrier privileges of any active subscription. @@ -256,6 +258,10 @@ public final class TelephonyPermissions { */ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId, String callingPackage, @Nullable String callingFeatureId, String message) { + if (checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, callingPackage, + callingFeatureId, message)) { + return true; + } return checkPrivilegedReadPermissionOrCarrierPrivilegePermission( context, subId, callingPackage, callingFeatureId, message, true); } @@ -267,7 +273,9 @@ public final class TelephonyPermissions { * <ul> * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier - * access check, or the calling package has carrier privileges on specified subscription. + * access check, or the calling package has carrier privileges on specified subscription, + * or the calling package has the {@link + * Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} appop permission. * <li>throw SecurityException: if the caller does not meet any of the requirements and is * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission. * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE @@ -278,6 +286,10 @@ public final class TelephonyPermissions { */ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId, String callingPackage, @Nullable String callingFeatureId, String message) { + if (checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, callingPackage, + callingFeatureId, message)) { + return true; + } return checkPrivilegedReadPermissionOrCarrierPrivilegePermission( context, subId, callingPackage, callingFeatureId, message, false); } @@ -315,8 +327,8 @@ public final class TelephonyPermissions { return true; } - PermissionManager permissionManager = (PermissionManager) context.getSystemService( - Context.PERMISSION_SERVICE); + LegacyPermissionManager permissionManager = (LegacyPermissionManager) + context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId, pid, uid) == PackageManager.PERMISSION_GRANTED) { return true; @@ -385,6 +397,40 @@ public final class TelephonyPermissions { } /** + * Check whether the caller (or self, if not processing an IPC) has {@link + * Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} AppOp permission. + * + * <p>With the permission, the caller can access device/subscriber identifiers and use ICC + * authentication like EAP-AKA. + */ + public static boolean checkCallingOrSelfUseIccAuthWithDeviceIdentifier(Context context, + String callingPackage, String callingFeatureId, String message) { + // The implementation follows PermissionChecker.checkAppOpPermission, but it cannot be + // used directly: because it uses noteProxyOpNoThrow which requires the phone process + // having the permission, which doesn't make sense since phone process is the ower of + // data/action. + // Cannot perform appop check if the calling package is null + if (callingPackage == null) { + return false; + } + int callingUid = Binder.getCallingUid(); + AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + int opMode = appOps.noteOpNoThrow(AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, + callingUid, callingPackage, callingFeatureId, message); + switch (opMode) { + case AppOpsManager.MODE_ALLOWED: + case AppOpsManager.MODE_FOREGROUND: + return true; + case AppOpsManager.MODE_DEFAULT: + return context.checkCallingOrSelfPermission( + Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER) + == PERMISSION_GRANTED; + default: + return false; + } + } + + /** * Check whether the app with the given pid/uid can read the call log. * @return {@code true} if the specified app has the read call log permission and AppOpp granted * to it, {@code false} otherwise. diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 02d741011220..125296540688 100644 --- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java @@ -99,7 +99,7 @@ public final class TelephonyUtils { */ public static void runWithCleanCallingIdentity( @NonNull Runnable action) { - long callingIdentity = Binder.clearCallingIdentity(); + final long callingIdentity = Binder.clearCallingIdentity(); try { action.run(); } finally { @@ -118,7 +118,7 @@ public final class TelephonyUtils { */ public static <T> T runWithCleanCallingIdentity( @NonNull Supplier<T> action) { - long callingIdentity = Binder.clearCallingIdentity(); + final long callingIdentity = Binder.clearCallingIdentity(); try { return action.get(); } finally { |