Loading services/core/java/com/android/server/pm/RestrictionsSet.java 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.os.Bundle; import android.os.UserManager; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * Data structure that contains the mapping of users to user restrictions (either the user * restrictions that apply to them, or the user restrictions that they set, depending on the * circumstances). * * @hide */ public class RestrictionsSet { private static final String USER_ID = "user_id"; private static final String TAG_RESTRICTIONS = "restrictions"; private static final String TAG_RESTRICTIONS_USER = "restrictions_user"; /** * Mapping of user restrictions. * Only non-empty restriction bundles are stored. * The key is the user id of the user. * userId -> restrictionBundle */ private final SparseArray<Bundle> mUserRestrictions = new SparseArray<>(0); public RestrictionsSet() { } public RestrictionsSet(@UserIdInt int userId, @NonNull Bundle restrictions) { if (restrictions.isEmpty()) { throw new IllegalArgumentException("empty restriction bundle cannot be added."); } mUserRestrictions.put(userId, restrictions); } /** * Updates restriction bundle for a given user. * If new bundle is empty, record is removed from the array. * * @return whether restrictions bundle is different from the old one. */ public boolean updateRestrictions(@UserIdInt int userId, @Nullable Bundle restrictions) { final boolean changed = !UserRestrictionsUtils.areEqual(mUserRestrictions.get(userId), restrictions); if (!changed) { return false; } if (!UserRestrictionsUtils.isEmpty(restrictions)) { mUserRestrictions.put(userId, restrictions); } else { mUserRestrictions.delete(userId); } return true; } /** * Moves a particular restriction from one restriction set to another, e.g. for all users. */ public void moveRestriction(@NonNull RestrictionsSet destRestrictions, String restriction) { for (int i = 0; i < mUserRestrictions.size(); i++) { final int userId = mUserRestrictions.keyAt(i); final Bundle from = mUserRestrictions.valueAt(i); if (UserRestrictionsUtils.contains(from, restriction)) { from.remove(restriction); Bundle to = destRestrictions.getRestrictions(userId); if (to == null) { to = new Bundle(); to.putBoolean(restriction, true); destRestrictions.updateRestrictions(userId, to); } else { to.putBoolean(restriction, true); } // Don't keep empty bundles. if (from.isEmpty()) { mUserRestrictions.removeAt(i); i--; } } } } /** * @return whether restrictions set has no restrictions. */ public boolean isEmpty() { return mUserRestrictions.size() == 0; } /** * Merge all restrictions in restrictions set into one bundle. The original user restrictions * set does not get modified, instead a new bundle is returned. * * @return restrictions bundle containing all user restrictions. */ public @NonNull Bundle mergeAll() { final Bundle result = new Bundle(); for (int i = 0; i < mUserRestrictions.size(); i++) { UserRestrictionsUtils.merge(result, mUserRestrictions.valueAt(i)); } return result; } /** * @return list of enforcing users that enforce a particular restriction. */ public @NonNull List<UserManager.EnforcingUser> getEnforcingUsers(String restriction, @UserIdInt int deviceOwnerUserId) { final List<UserManager.EnforcingUser> result = new ArrayList<>(); for (int i = 0; i < mUserRestrictions.size(); i++) { if (UserRestrictionsUtils.contains(mUserRestrictions.valueAt(i), restriction)) { result.add(getEnforcingUser(mUserRestrictions.keyAt(i), deviceOwnerUserId)); } } return result; } private UserManager.EnforcingUser getEnforcingUser(@UserIdInt int userId, @UserIdInt int deviceOwnerUserId) { int source = deviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER; return new UserManager.EnforcingUser(userId, source); } /** * @return list of user restrictions for a given user. Null is returned if the user does not * have any restrictions. */ public @Nullable Bundle getRestrictions(@UserIdInt int userId) { return mUserRestrictions.get(userId); } /** * Removes a given user from the restrictions set, returning true if the user has non-empty * restrictions before removal. */ public boolean remove(@UserIdInt int userId) { boolean hasUserRestriction = mUserRestrictions.contains(userId); mUserRestrictions.remove(userId); return hasUserRestriction; } /** * Remove list of users and user restrictions. */ public void removeAllRestrictions() { mUserRestrictions.clear(); } /** * Serialize a given {@link RestrictionsSet} to XML. */ public void writeRestrictions(@NonNull XmlSerializer serializer, @NonNull String outerTag) throws IOException { serializer.startTag(null, outerTag); for (int i = 0; i < mUserRestrictions.size(); i++) { serializer.startTag(null, TAG_RESTRICTIONS_USER); serializer.attribute(null, USER_ID, String.valueOf(mUserRestrictions.keyAt(i))); UserRestrictionsUtils.writeRestrictions(serializer, mUserRestrictions.valueAt(i), TAG_RESTRICTIONS); serializer.endTag(null, TAG_RESTRICTIONS_USER); } serializer.endTag(null, outerTag); } /** * Read restrictions from XML. */ public static RestrictionsSet readRestrictions(@NonNull XmlPullParser parser, @NonNull String outerTag) throws IOException, XmlPullParserException { RestrictionsSet restrictionsSet = new RestrictionsSet(); int userId = 0; int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { String tag = parser.getName(); if (type == XmlPullParser.END_TAG && outerTag.equals(tag)) { return restrictionsSet; } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS_USER.equals(tag)) { userId = Integer.parseInt(parser.getAttributeValue(null, USER_ID)); } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS.equals(tag)) { Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser); restrictionsSet.updateRestrictions(userId, restrictions); } } throw new XmlPullParserException("restrictions cannot be read as xml is malformed."); } /** * Dumps {@link RestrictionsSet}. */ public void dumpRestrictions(PrintWriter pw, String prefix) { boolean noneSet = true; for (int i = 0; i < mUserRestrictions.size(); i++) { pw.println(prefix + "User Id: " + mUserRestrictions.keyAt(i)); UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mUserRestrictions.valueAt(i)); noneSet = false; } if (noneSet) { pw.println(prefix + "none"); } } public boolean containsKey(@UserIdInt int userId) { return mUserRestrictions.contains(userId); } @VisibleForTesting public int size() { return mUserRestrictions.size(); } @VisibleForTesting public int keyAt(int index) { return mUserRestrictions.keyAt(index); } @VisibleForTesting public Bundle valueAt(int index) { return mUserRestrictions.valueAt(index); } } Loading
services/core/java/com/android/server/pm/RestrictionsSet.java 0 → 100644 +256 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.os.Bundle; import android.os.UserManager; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * Data structure that contains the mapping of users to user restrictions (either the user * restrictions that apply to them, or the user restrictions that they set, depending on the * circumstances). * * @hide */ public class RestrictionsSet { private static final String USER_ID = "user_id"; private static final String TAG_RESTRICTIONS = "restrictions"; private static final String TAG_RESTRICTIONS_USER = "restrictions_user"; /** * Mapping of user restrictions. * Only non-empty restriction bundles are stored. * The key is the user id of the user. * userId -> restrictionBundle */ private final SparseArray<Bundle> mUserRestrictions = new SparseArray<>(0); public RestrictionsSet() { } public RestrictionsSet(@UserIdInt int userId, @NonNull Bundle restrictions) { if (restrictions.isEmpty()) { throw new IllegalArgumentException("empty restriction bundle cannot be added."); } mUserRestrictions.put(userId, restrictions); } /** * Updates restriction bundle for a given user. * If new bundle is empty, record is removed from the array. * * @return whether restrictions bundle is different from the old one. */ public boolean updateRestrictions(@UserIdInt int userId, @Nullable Bundle restrictions) { final boolean changed = !UserRestrictionsUtils.areEqual(mUserRestrictions.get(userId), restrictions); if (!changed) { return false; } if (!UserRestrictionsUtils.isEmpty(restrictions)) { mUserRestrictions.put(userId, restrictions); } else { mUserRestrictions.delete(userId); } return true; } /** * Moves a particular restriction from one restriction set to another, e.g. for all users. */ public void moveRestriction(@NonNull RestrictionsSet destRestrictions, String restriction) { for (int i = 0; i < mUserRestrictions.size(); i++) { final int userId = mUserRestrictions.keyAt(i); final Bundle from = mUserRestrictions.valueAt(i); if (UserRestrictionsUtils.contains(from, restriction)) { from.remove(restriction); Bundle to = destRestrictions.getRestrictions(userId); if (to == null) { to = new Bundle(); to.putBoolean(restriction, true); destRestrictions.updateRestrictions(userId, to); } else { to.putBoolean(restriction, true); } // Don't keep empty bundles. if (from.isEmpty()) { mUserRestrictions.removeAt(i); i--; } } } } /** * @return whether restrictions set has no restrictions. */ public boolean isEmpty() { return mUserRestrictions.size() == 0; } /** * Merge all restrictions in restrictions set into one bundle. The original user restrictions * set does not get modified, instead a new bundle is returned. * * @return restrictions bundle containing all user restrictions. */ public @NonNull Bundle mergeAll() { final Bundle result = new Bundle(); for (int i = 0; i < mUserRestrictions.size(); i++) { UserRestrictionsUtils.merge(result, mUserRestrictions.valueAt(i)); } return result; } /** * @return list of enforcing users that enforce a particular restriction. */ public @NonNull List<UserManager.EnforcingUser> getEnforcingUsers(String restriction, @UserIdInt int deviceOwnerUserId) { final List<UserManager.EnforcingUser> result = new ArrayList<>(); for (int i = 0; i < mUserRestrictions.size(); i++) { if (UserRestrictionsUtils.contains(mUserRestrictions.valueAt(i), restriction)) { result.add(getEnforcingUser(mUserRestrictions.keyAt(i), deviceOwnerUserId)); } } return result; } private UserManager.EnforcingUser getEnforcingUser(@UserIdInt int userId, @UserIdInt int deviceOwnerUserId) { int source = deviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER; return new UserManager.EnforcingUser(userId, source); } /** * @return list of user restrictions for a given user. Null is returned if the user does not * have any restrictions. */ public @Nullable Bundle getRestrictions(@UserIdInt int userId) { return mUserRestrictions.get(userId); } /** * Removes a given user from the restrictions set, returning true if the user has non-empty * restrictions before removal. */ public boolean remove(@UserIdInt int userId) { boolean hasUserRestriction = mUserRestrictions.contains(userId); mUserRestrictions.remove(userId); return hasUserRestriction; } /** * Remove list of users and user restrictions. */ public void removeAllRestrictions() { mUserRestrictions.clear(); } /** * Serialize a given {@link RestrictionsSet} to XML. */ public void writeRestrictions(@NonNull XmlSerializer serializer, @NonNull String outerTag) throws IOException { serializer.startTag(null, outerTag); for (int i = 0; i < mUserRestrictions.size(); i++) { serializer.startTag(null, TAG_RESTRICTIONS_USER); serializer.attribute(null, USER_ID, String.valueOf(mUserRestrictions.keyAt(i))); UserRestrictionsUtils.writeRestrictions(serializer, mUserRestrictions.valueAt(i), TAG_RESTRICTIONS); serializer.endTag(null, TAG_RESTRICTIONS_USER); } serializer.endTag(null, outerTag); } /** * Read restrictions from XML. */ public static RestrictionsSet readRestrictions(@NonNull XmlPullParser parser, @NonNull String outerTag) throws IOException, XmlPullParserException { RestrictionsSet restrictionsSet = new RestrictionsSet(); int userId = 0; int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { String tag = parser.getName(); if (type == XmlPullParser.END_TAG && outerTag.equals(tag)) { return restrictionsSet; } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS_USER.equals(tag)) { userId = Integer.parseInt(parser.getAttributeValue(null, USER_ID)); } else if (type == XmlPullParser.START_TAG && TAG_RESTRICTIONS.equals(tag)) { Bundle restrictions = UserRestrictionsUtils.readRestrictions(parser); restrictionsSet.updateRestrictions(userId, restrictions); } } throw new XmlPullParserException("restrictions cannot be read as xml is malformed."); } /** * Dumps {@link RestrictionsSet}. */ public void dumpRestrictions(PrintWriter pw, String prefix) { boolean noneSet = true; for (int i = 0; i < mUserRestrictions.size(); i++) { pw.println(prefix + "User Id: " + mUserRestrictions.keyAt(i)); UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mUserRestrictions.valueAt(i)); noneSet = false; } if (noneSet) { pw.println(prefix + "none"); } } public boolean containsKey(@UserIdInt int userId) { return mUserRestrictions.contains(userId); } @VisibleForTesting public int size() { return mUserRestrictions.size(); } @VisibleForTesting public int keyAt(int index) { return mUserRestrictions.keyAt(index); } @VisibleForTesting public Bundle valueAt(int index) { return mUserRestrictions.valueAt(index); } }