diff options
4 files changed, 207 insertions, 10 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index 21b12914bc4c..333be3ad26ed 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -21,6 +21,7 @@ import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_TARGET_USER_ID import static android.app.admin.PolicyUpdateReceiver.EXTRA_POLICY_UPDATE_RESULT_KEY; import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_CONFLICTING_ADMIN_POLICY; import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_HARDWARE_LIMITATION; +import static android.app.admin.PolicyUpdateResult.RESULT_FAILURE_STORAGE_LIMIT_REACHED; import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_CLEARED; import static android.app.admin.PolicyUpdateResult.RESULT_POLICY_SET; import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT; @@ -51,6 +52,7 @@ import android.content.pm.UserProperties; import android.os.Binder; import android.os.Bundle; import android.os.Environment; +import android.os.Parcel; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -63,6 +65,7 @@ import android.util.Xml; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; +import com.android.server.devicepolicy.flags.FlagUtils; import com.android.server.utils.Slogf; import libcore.io.IoUtils; @@ -117,6 +120,10 @@ final class DevicePolicyEngine { * Map containing the current set of admins in each user with active policies. */ private final SparseArray<Set<EnforcingAdmin>> mEnforcingAdmins; + private final SparseArray<HashMap<EnforcingAdmin, Integer>> mAdminPolicySize; + + //TODO(b/295504706) : Speak to security team to decide what to set Policy_Size_Limit + private static final int POLICY_SIZE_LIMIT = 99999; private final DeviceAdminServiceController mDeviceAdminServiceController; @@ -131,6 +138,7 @@ final class DevicePolicyEngine { mLocalPolicies = new SparseArray<>(); mGlobalPolicies = new HashMap<>(); mEnforcingAdmins = new SparseArray<>(); + mAdminPolicySize = new SparseArray<>(); } /** @@ -139,7 +147,6 @@ final class DevicePolicyEngine { * * <p>If {@code skipEnforcePolicy} is true, it sets the policies in the internal data structure * but doesn't call the enforcing logic. - * */ <V> void setLocalPolicy( @NonNull PolicyDefinition<V> policyDefinition, @@ -152,6 +159,12 @@ final class DevicePolicyEngine { synchronized (mLock) { PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId); + if (FlagUtils.isDevicePolicySizeTrackingEnabled()) { + if (!handleAdminPolicySizeLimit(localPolicyState, enforcingAdmin, value, + policyDefinition, userId)) { + return; + } + } if (policyDefinition.isNonCoexistablePolicy()) { setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState, @@ -236,6 +249,7 @@ final class DevicePolicyEngine { } // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values + /** * Set the policy for the provided {@code policyDefinition} * (see {@link PolicyDefinition}) and {@code enforcingAdmin} to the provided {@code value}. @@ -250,6 +264,7 @@ final class DevicePolicyEngine { } // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values + /** * Removes any previously set policy for the provided {@code policyDefinition} * (see {@link PolicyDefinition}) and {@code enforcingAdmin}. @@ -267,6 +282,10 @@ final class DevicePolicyEngine { } PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId); + if (FlagUtils.isDevicePolicySizeTrackingEnabled()) { + decreasePolicySizeForAdmin(localPolicyState, enforcingAdmin); + } + if (policyDefinition.isNonCoexistablePolicy()) { setNonCoexistableLocalPolicyLocked(policyDefinition, localPolicyState, enforcingAdmin, /* value= */ null, userId, /* skipEnforcePolicy= */ false); @@ -392,6 +411,7 @@ final class DevicePolicyEngine { } // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values + /** * Set the policy for the provided {@code policyDefinition} * (see {@link PolicyDefinition}) and {@code enforcingAdmin} to the provided {@code value}. @@ -407,6 +427,13 @@ final class DevicePolicyEngine { Objects.requireNonNull(value); synchronized (mLock) { + PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition); + if (FlagUtils.isDevicePolicySizeTrackingEnabled()) { + if (!handleAdminPolicySizeLimit(globalPolicyState, enforcingAdmin, value, + policyDefinition, UserHandle.USER_ALL)) { + return; + } + } // TODO(b/270999567): Move error handling for DISALLOW_CELLULAR_2G into the code // that honors the restriction once there's an API available if (checkFor2gFailure(policyDefinition, enforcingAdmin)) { @@ -416,8 +443,6 @@ final class DevicePolicyEngine { return; } - PolicyState<V> globalPolicyState = getGlobalPolicyStateLocked(policyDefinition); - boolean policyChanged = globalPolicyState.addPolicy(enforcingAdmin, value); boolean policyAppliedOnAllUsers = applyGlobalPolicyOnUsersWithLocalPoliciesLocked( policyDefinition, enforcingAdmin, value, skipEnforcePolicy); @@ -434,7 +459,7 @@ final class DevicePolicyEngine { // TODO(b/285532044): remove hack and handle properly if (!policyAppliedGlobally && policyDefinition.getPolicyKey().getIdentifier().equals( - USER_CONTROL_DISABLED_PACKAGES_POLICY)) { + USER_CONTROL_DISABLED_PACKAGES_POLICY)) { PolicyValue<Set<String>> parsedValue = (PolicyValue<Set<String>>) value; PolicyValue<Set<String>> parsedResolvedValue = (PolicyValue<Set<String>>) globalPolicyState.getCurrentResolvedPolicy(); @@ -459,6 +484,7 @@ final class DevicePolicyEngine { } // TODO: add more documentation on broadcasts/callbacks to use to get current enforced values + /** * Removes any previously set policy for the provided {@code policyDefinition} * (see {@link PolicyDefinition}) and {@code enforcingAdmin}. @@ -472,6 +498,11 @@ final class DevicePolicyEngine { synchronized (mLock) { PolicyState<V> policyState = getGlobalPolicyStateLocked(policyDefinition); + + if (FlagUtils.isDevicePolicySizeTrackingEnabled()) { + decreasePolicySizeForAdmin(policyState, enforcingAdmin); + } + boolean policyChanged = policyState.removePolicy(enforcingAdmin); if (policyChanged) { @@ -687,7 +718,6 @@ final class DevicePolicyEngine { * <p>Note that this will always return at most one item for policies that do not require * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}). - * */ @NonNull <V> Set<PolicyKey> getLocalPolicyKeysSetByAdmin( @@ -723,7 +753,6 @@ final class DevicePolicyEngine { * <p>Note that this will always return at most one item for policies that do not require * additional params (e.g. {@link PolicyDefinition#LOCK_TASK} vs * {@link PolicyDefinition#PERMISSION_GRANT(String, String)}). - * */ @NonNull <V> Set<PolicyKey> getLocalPolicyKeysSetByAllAdmins( @@ -964,7 +993,7 @@ final class DevicePolicyEngine { EnforcingAdmin callingAdmin, PolicyDefinition<V> policyDefinition, int userId) { - for (EnforcingAdmin admin: policyState.getPoliciesSetByAdmins().keySet()) { + for (EnforcingAdmin admin : policyState.getPoliciesSetByAdmins().keySet()) { // We're sending a separate broadcast for the calling admin with the result. if (admin.equals(callingAdmin)) { continue; @@ -1152,7 +1181,7 @@ final class DevicePolicyEngine { try { if (packageManager.getPackageInfo(packageName, 0, userId) == null || packageManager.getActivityInfo( - policies.get(admin).getValue(), 0, userId) == null) { + policies.get(admin).getValue(), 0, userId) == null) { Slogf.e(TAG, String.format( "Persistent preferred activity in package %s not found for " + "user %d, removing policy for admin", @@ -1450,6 +1479,97 @@ final class DevicePolicyEngine { return false; } + /** + * Calculate the size of a policy in bytes + */ + + private static <V> int sizeOf(PolicyValue<V> value) { + try { + Parcel parcel = Parcel.obtain(); + parcel.writeParcelable(value, /* flags= */ 0); + + parcel.setDataPosition(0); + + byte[] bytes; + + bytes = parcel.marshall(); + return bytes.length; + } catch (Exception e) { + Log.e(TAG, "Error calculating size of policy: " + e); + return 0; + } + } + + /** + * Checks if the policy already exists and removes the current size to prevent recording the + * same policy twice. + * + * Checks if the new sum of the size of all policies is less than the maximum sum of policies + * size per admin and returns true. + * + * If the policy size limit is reached then send policy result to admin and return false. + */ + + private <V> boolean handleAdminPolicySizeLimit(PolicyState<V> policyState, EnforcingAdmin admin, + PolicyValue<V> value, PolicyDefinition policyDefinition, int userId) { + int currentSize = 0; + if (mAdminPolicySize.contains(admin.getUserId()) + && mAdminPolicySize.get( + admin.getUserId()).containsKey(admin)) { + currentSize = mAdminPolicySize.get(admin.getUserId()).get(admin); + } + if (policyState.getPoliciesSetByAdmins().containsKey(admin)) { + currentSize -= sizeOf(policyState.getPoliciesSetByAdmins().get(admin)); + } + int policySize = sizeOf(value); + if (currentSize + policySize < POLICY_SIZE_LIMIT) { + increasePolicySizeForAdmin(admin, policySize); + return true; + } else { + sendPolicyResultToAdmin( + admin, + policyDefinition, + RESULT_FAILURE_STORAGE_LIMIT_REACHED, + userId); + return false; + } + } + + /** + * Increase the int in mAdminPolicySize representing the size of the sum of all + * active policies for that admin. + */ + + private <V> void increasePolicySizeForAdmin(EnforcingAdmin admin, int policySize) { + if (!mAdminPolicySize.contains(admin.getUserId())) { + mAdminPolicySize.put(admin.getUserId(), new HashMap<>()); + } + if (!mAdminPolicySize.get(admin.getUserId()).containsKey(admin)) { + mAdminPolicySize.get(admin.getUserId()).put(admin, /* size= */ 0); + } + mAdminPolicySize.get(admin.getUserId()).put(admin, + mAdminPolicySize.get(admin.getUserId()).get(admin) + policySize); + } + + /** + * Decrease the int in mAdminPolicySize representing the size of the sum of all + * active policies for that admin. + */ + + private <V> void decreasePolicySizeForAdmin(PolicyState<V> policyState, EnforcingAdmin admin) { + if (policyState.getPoliciesSetByAdmins().containsKey(admin)) { + mAdminPolicySize.get(admin.getUserId()).put(admin, + mAdminPolicySize.get(admin.getUserId()).get(admin) - sizeOf( + policyState.getPoliciesSetByAdmins().get(admin))); + } + if (mAdminPolicySize.get(admin.getUserId()).get(admin) <= 0) { + mAdminPolicySize.get(admin.getUserId()).remove(admin); + } + if (mAdminPolicySize.get(admin.getUserId()).isEmpty()) { + mAdminPolicySize.remove(admin.getUserId()); + } + } + @NonNull private Set<EnforcingAdmin> getEnforcingAdminsOnUser(int userId) { synchronized (mLock) { @@ -1509,11 +1629,13 @@ final class DevicePolicyEngine { clear(); write(); } + private void clear() { synchronized (mLock) { mGlobalPolicies.clear(); mLocalPolicies.clear(); mEnforcingAdmins.clear(); + mAdminPolicySize.clear(); } } @@ -1554,7 +1676,11 @@ final class DevicePolicyEngine { private static final String TAG_POLICY_STATE_ENTRY = "policy-state-entry"; private static final String TAG_POLICY_KEY_ENTRY = "policy-key-entry"; private static final String TAG_ENFORCING_ADMINS_ENTRY = "enforcing-admins-entry"; + private static final String TAG_ENFORCING_ADMIN_AND_SIZE = "enforcing-admin-and-size"; + private static final String TAG_ENFORCING_ADMIN = "enforcing-admin"; + private static final String TAG_POLICY_SUM_SIZE = "policy-sum-size"; private static final String ATTR_USER_ID = "user-id"; + private static final String ATTR_POLICY_SUM_SIZE = "size"; private final File mFile; @@ -1596,6 +1722,7 @@ final class DevicePolicyEngine { writeLocalPoliciesInner(serializer); writeGlobalPoliciesInner(serializer); writeEnforcingAdminsInner(serializer); + writeEnforcingAdminSizeInner(serializer); } private void writeLocalPoliciesInner(TypedXmlSerializer serializer) throws IOException { @@ -1653,6 +1780,30 @@ final class DevicePolicyEngine { } } + private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer) + throws IOException { + if (FlagUtils.isDevicePolicySizeTrackingEnabled()) { + if (mAdminPolicySize != null) { + for (int i = 0; i < mAdminPolicySize.size(); i++) { + int userId = mAdminPolicySize.keyAt(i); + for (EnforcingAdmin admin : mAdminPolicySize.get( + userId).keySet()) { + serializer.startTag(/* namespace= */ null, + TAG_ENFORCING_ADMIN_AND_SIZE); + serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN); + admin.saveToXml(serializer); + serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN); + serializer.startTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE); + serializer.attributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE, + mAdminPolicySize.get(userId).get(admin)); + serializer.endTag(/* namespace= */ null, TAG_POLICY_SUM_SIZE); + serializer.endTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_AND_SIZE); + } + } + } + } + } + void readFromFileLocked() { if (!mFile.exists()) { Log.d(TAG, "" + mFile + " doesn't exist"); @@ -1690,6 +1841,9 @@ final class DevicePolicyEngine { case TAG_ENFORCING_ADMINS_ENTRY: readEnforcingAdminsInner(parser); break; + case TAG_ENFORCING_ADMIN_AND_SIZE: + readEnforcingAdminAndSizeInner(parser); + break; default: Slogf.wtf(TAG, "Unknown tag " + tag); } @@ -1768,5 +1922,37 @@ final class DevicePolicyEngine { } mEnforcingAdmins.get(admin.getUserId()).add(admin); } + + private void readEnforcingAdminAndSizeInner(TypedXmlPullParser parser) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + EnforcingAdmin admin = null; + int size = 0; + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + String tag = parser.getName(); + switch (tag) { + case TAG_ENFORCING_ADMIN: + admin = EnforcingAdmin.readFromXml(parser); + break; + case TAG_POLICY_SUM_SIZE: + size = parser.getAttributeInt(/* namespace= */ null, ATTR_POLICY_SUM_SIZE); + break; + default: + Slogf.wtf(TAG, "Unknown tag " + tag); + } + } + if (admin == null) { + Slogf.wtf(TAG, "Error parsing enforcingAdmins, EnforcingAdmin is null."); + return; + } + if (size <= 0) { + Slogf.wtf(TAG, "Error parsing policy size, size is " + size); + return; + } + if (!mAdminPolicySize.contains(admin.getUserId())) { + mAdminPolicySize.put(admin.getUserId(), new HashMap<>()); + } + mAdminPolicySize.get(admin.getUserId()).put(admin, size); + } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 50dc061c1ab2..9f800f69c78e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -241,7 +241,6 @@ import static android.provider.Telephony.Carriers.ENFORCE_KEY; import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI; import static android.provider.Telephony.Carriers.INVALID_APN_ID; import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION; - import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; @@ -23362,7 +23361,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public DevicePolicyState getDevicePolicyState() { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); - return mInjector.binderWithCleanCallingIdentity(mDevicePolicyEngine::getDevicePolicyState); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/flags/FlagUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/flags/FlagUtils.java index 9fe3749755da..7e17ef111cf0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/flags/FlagUtils.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/flags/FlagUtils.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy.flags; +import static com.android.server.devicepolicy.flags.Flags.devicePolicySizeTrackingEnabled; import static com.android.server.devicepolicy.flags.Flags.policyEngineMigrationV2Enabled; import android.os.Binder; @@ -28,4 +29,10 @@ public final class FlagUtils { return policyEngineMigrationV2Enabled(); }); } + + public static boolean isDevicePolicySizeTrackingEnabled() { + return Binder.withCleanCallingIdentity(() -> { + return devicePolicySizeTrackingEnabled(); + }); + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig b/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig index 00702a9c26fa..0dde496e7285 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig +++ b/services/devicepolicy/java/com/android/server/devicepolicy/flags/flags.aconfig @@ -5,4 +5,10 @@ flag { namespace: "enterprise" description: "V2 of the policy engine migrations for Android V" bug: "289520697" +} +flag { + name: "device_policy_size_tracking_enabled" + namespace: "enterprise" + description: "Add feature to track the total policy size and have a max threshold." + bug: "281543351" }
\ No newline at end of file |