From 39839dc63b20ab615ce0116ccd417d87d5004ad7 Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Fri, 27 Dec 2019 14:21:58 -0800 Subject: [PATCH] Create new APIs for overriding APNs Create new APIs in TelephonyManager for DevicePolicyManager to add override APNs, and use them in DevicePolicyManagerService instead of directly accessing the APN database. Bug: 146834818 Test: cts-tradefed run cts --module DevicePolicyManager --test com.android.cts.devicepolicy.DeviceOwnerTest#testOverrideApn Test: atest TelephonyManagerTest Change-Id: I6c6214424169c05fd452db71a8c6593f8473b9d4 Merged-In: I6c6214424169c05fd452db71a8c6593f8473b9d4 --- api/system-current.txt | 5 ++ api/test-current.txt | 3 + core/java/android/provider/Telephony.java | 10 ++- .../DevicePolicyManagerService.java | 70 ++++++--------- .../server/devicepolicy/DpmMockContext.java | 2 + .../android/telephony/TelephonyManager.java | 86 +++++++++++++++++++ 6 files changed, 131 insertions(+), 45 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 8388654dbcd9e..e9afb22eb6fbb 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6718,7 +6718,9 @@ package android.provider { public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final String APN_SET_ID = "apn_set_id"; field public static final int CARRIER_EDITED = 4; // 0x4 + field @NonNull public static final android.net.Uri DPC_URI; field public static final String EDITED_STATUS = "edited"; + field public static final int INVALID_APN_ID = -1; // 0xffffffff field public static final String MAX_CONNECTIONS = "max_conns"; field public static final String MODEM_PERSIST = "modem_cognitive"; field public static final String MTU = "mtu"; @@ -8916,6 +8918,7 @@ package android.telephony { } public class TelephonyManager { + method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method public int checkCarrierPrivilegesForPackage(String); method public int checkCarrierPrivilegesForPackageAnyPhone(String); @@ -8942,6 +8945,7 @@ package android.telephony { method @Deprecated public boolean getDataEnabled(); method @Deprecated public boolean getDataEnabled(int); method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean); + method @NonNull public java.util.List getDevicePolicyOverrideApns(@NonNull android.content.Context); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); method public int getEmergencyNumberDbVersion(); @@ -8985,6 +8989,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); + method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method public boolean needsOtaServiceProvisioning(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); diff --git a/api/test-current.txt b/api/test-current.txt index 44498dd16b877..064072fb9dd8e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3036,14 +3036,17 @@ package android.telephony { } public class TelephonyManager { + method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting); method public int checkCarrierPrivilegesForPackage(String); method public int getCarrierIdListVersion(); method public java.util.List getCarrierPackageNamesForIntent(android.content.Intent); method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean); + method @NonNull public java.util.List getDevicePolicyOverrideApns(@NonNull android.content.Context); method public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int); method public android.util.Pair getRadioHalVersion(); + method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String); diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index df36f143393b9..13d167d5e99aa 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -3522,7 +3522,8 @@ public final class Telephony { * can manage DPC-owned APNs. * @hide */ - public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc"); + @SystemApi + public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc"); /** * The {@code content://} style URL to be called from Telephony to query APNs. @@ -3830,6 +3831,13 @@ public final class Telephony { @SystemApi public static final String USER_EDITABLE = "user_editable"; + /** + * Integer value denoting an invalid APN id + * @hide + */ + @SystemApi + public static final int INVALID_APN_ID = -1; + /** * {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or * fails to edit. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 127b8e016d150..952a64cb2d7c1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -206,6 +206,7 @@ import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings.Global; +import android.provider.Telephony; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; @@ -246,6 +247,7 @@ import com.android.internal.telephony.SmsApplication; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; +import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import com.android.internal.util.JournaledFile; import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; @@ -2061,6 +2063,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Binder.withCleanCallingIdentity(action); } + final T binderWithCleanCallingIdentity(@NonNull ThrowingSupplier action) { + return Binder.withCleanCallingIdentity(action); + } + final int userHandleGetCallingUserId() { return UserHandle.getUserId(binderGetCallingUid()); } @@ -13936,23 +13942,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn"); enforceDeviceOwner(who); - int operatedId = -1; - Uri resultUri; - final long id = mInjector.binderClearCallingIdentity(); - try { - resultUri = mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()); - } finally { - mInjector.binderRestoreCallingIdentity(id); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.addDevicePolicyOverrideApn(mContext, apnSetting)); + } else { + Log.w(LOG_TAG, "TelephonyManager is null when trying to add override apn"); + return Telephony.Carriers.INVALID_APN_ID; } - if (resultUri != null) { - try { - operatedId = Integer.parseInt(resultUri.getLastPathSegment()); - } catch (NumberFormatException e) { - Slog.e(LOG_TAG, "Failed to parse inserted override APN id.", e); - } - } - - return operatedId; } @Override @@ -13968,13 +13965,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (apnId < 0) { return false; } - final long id = mInjector.binderClearCallingIdentity(); - try { - return mContext.getContentResolver().update( - Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), - apnSetting.toContentValues(), null, null) > 0; - } finally { - mInjector.binderRestoreCallingIdentity(id); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.modifyDevicePolicyOverrideApn(mContext, apnId, apnSetting)); + } else { + Log.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn"); + return false; } } @@ -14016,28 +14013,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private List getOverrideApnsUnchecked() { - final Cursor cursor; - final long id = mInjector.binderClearCallingIdentity(); - try { - cursor = mContext.getContentResolver().query(DPC_URI, null, null, null, null); - } finally { - mInjector.binderRestoreCallingIdentity(id); - } - - if (cursor == null) { - return Collections.emptyList(); - } - try { - List apnList = new ArrayList(); - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - apnList.add(apn); - } - return apnList; - } finally { - cursor.close(); + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm != null) { + return mInjector.binderWithCleanCallingIdentity( + () -> tm.getDevicePolicyOverrideApns(mContext)); } + Log.w(LOG_TAG, "TelephonyManager is null when trying to get override apns"); + return Collections.emptyList(); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 1a67576c218f7..960f670904d6d 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -217,6 +217,8 @@ public class DpmMockContext extends MockContext { return mMockSystemServices.wifiManager; case Context.ACCOUNT_SERVICE: return mMockSystemServices.accountManager; + case Context.TELEPHONY_SERVICE: + return mMockSystemServices.telephonyManager; } throw new UnsupportedOperationException(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 12d8707bea5a2..82315e3588418 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -17,6 +17,8 @@ package android.telephony; import static android.content.Context.TELECOM_SERVICE; +import static android.provider.Telephony.Carriers.DPC_URI; +import static android.provider.Telephony.Carriers.INVALID_APN_ID; import static com.android.internal.util.Preconditions.checkNotNull; @@ -44,6 +46,7 @@ import android.compat.annotation.EnabledAfter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkStats; import android.net.Uri; @@ -75,6 +78,7 @@ import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.VisualVoicemailService.VisualVoicemailTask; +import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; import android.telephony.ims.ImsMmTelManager; @@ -11667,6 +11671,88 @@ public class TelephonyManager { return new Pair(-1, -1); } + /** + * Returns a list of APNs set as overrides by the device policy manager via + * {@link #addDevicePolicyOverrideApn}. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @return {@link List} of APNs that have been set as overrides. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public @NonNull List getDevicePolicyOverrideApns(@NonNull Context context) { + try (Cursor cursor = context.getContentResolver().query(DPC_URI, null, null, null, null)) { + if (cursor == null) { + return Collections.emptyList(); + } + List apnList = new ArrayList(); + cursor.moveToPosition(-1); + while (cursor.moveToNext()) { + ApnSetting apn = ApnSetting.makeApnSetting(cursor); + apnList.add(apn); + } + return apnList; + } + } + + /** + * Used by the device policy manager to add a new override APN. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @param apnSetting The {@link ApnSetting} describing the new APN. + * @return An integer, corresponding to a primary key in a database, that allows the caller to + * modify the APN in the future via {@link #modifyDevicePolicyOverrideApn}, or + * {@link android.provider.Telephony.Carriers.INVALID_APN_ID} if the override operation + * failed. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public int addDevicePolicyOverrideApn(@NonNull Context context, + @NonNull ApnSetting apnSetting) { + Uri resultUri = context.getContentResolver().insert(DPC_URI, apnSetting.toContentValues()); + + int resultId = INVALID_APN_ID; + if (resultUri != null) { + try { + resultId = Integer.parseInt(resultUri.getLastPathSegment()); + } catch (NumberFormatException e) { + Rlog.e(TAG, "Failed to parse inserted override APN id: " + + resultUri.getLastPathSegment()); + } + } + return resultId; + } + + /** + * Used by the device policy manager to modify an override APN. + * This method must only be called from the system or phone processes. + * + * @param context Context to use. + * @param apnId The integer key of the APN to modify, as returned by + * {@link #addDevicePolicyOverrideApn} + * @param apnSetting The {@link ApnSetting} describing the updated APN. + * @return {@code true} if successful, {@code false} otherwise. + * @throws {@link SecurityException} if the caller is not the system or phone process. + * @hide + */ + @SystemApi + @TestApi + // TODO: add new permission tag indicating that this is system-only. + public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId, + @NonNull ApnSetting apnSetting) { + return context.getContentResolver().update( + Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), + apnSetting.toContentValues(), null, null) > 0; + } + /** * Return whether data is enabled for certain APN type. This will tell if framework will accept * corresponding network requests on a subId.