Loading apct-tests/perftests/multiuser/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application> <application> <uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" /> Loading apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +77 −0 Original line number Original line Diff line number Diff line Loading @@ -38,8 +38,10 @@ import android.os.Bundle; import android.os.IBinder; import android.os.IBinder; import android.os.IProgressListener; import android.os.IProgressListener; import android.os.RemoteException; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager; import android.perftests.utils.ShellHelper; import android.util.Log; import android.util.Log; import android.view.WindowManagerGlobal; import android.view.WindowManagerGlobal; Loading Loading @@ -85,6 +87,14 @@ public class UserLifecycleTests { private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp"; private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp"; // Copy of UserSystemPackageInstaller whitelist mode constants. private static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode"; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1; private UserManager mUm; private UserManager mUm; private ActivityManager mAm; private ActivityManager mAm; private IActivityManager mIam; private IActivityManager mIam; Loading Loading @@ -442,6 +452,55 @@ public class UserLifecycleTests { } } } } // TODO: This is just a POC. Do this properly and add more. /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */ @Test public void managedProfileUnlock_usingWhitelist() throws Exception { assumeTrue(mHasManagedUserFeature); final int origMode = getUserTypePackageWhitelistMode(); setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST); try { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int userId = createManagedProfile(); mRunner.resumeTiming(); startUserInBackground(userId); mRunner.pauseTiming(); removeUser(userId); mRunner.resumeTiming(); } } finally { setUserTypePackageWhitelistMode(origMode); } } /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */ @Test public void managedProfileUnlock_notUsingWhitelist() throws Exception { assumeTrue(mHasManagedUserFeature); final int origMode = getUserTypePackageWhitelistMode(); setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE); try { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int userId = createManagedProfile(); mRunner.resumeTiming(); startUserInBackground(userId); mRunner.pauseTiming(); removeUser(userId); mRunner.resumeTiming(); } } finally { setUserTypePackageWhitelistMode(origMode); } } /** Creates a new user, returning its userId. */ /** Creates a new user, returning its userId. */ private int createUserNoFlags() { private int createUserNoFlags() { return createUserWithFlags(/* flags= */ 0); return createUserWithFlags(/* flags= */ 0); Loading @@ -458,6 +517,10 @@ public class UserLifecycleTests { private int createManagedProfile() { private int createManagedProfile() { final UserInfo userInfo = mUm.createProfileForUser("TestProfile", final UserInfo userInfo = mUm.createProfileForUser("TestProfile", UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); if (userInfo == null) { throw new IllegalStateException("Creating managed profile failed. Most likely there is " + "already a pre-existing profile on the device."); } mUsersToRemove.add(userInfo.id); mUsersToRemove.add(userInfo.id); return userInfo.id; return userInfo.id; } } Loading Loading @@ -627,6 +690,20 @@ public class UserLifecycleTests { } } } } /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */ private int getUserTypePackageWhitelistMode() { return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); } /** Sets the PACKAGE_WHITELIST_MODE_PROP System Property to the given value. */ private void setUserTypePackageWhitelistMode(int mode) { String result = ShellHelper.runShellCommand( String.format("setprop %s %d", PACKAGE_WHITELIST_MODE_PROP, mode)); attestFalse("Failed to set sysprop " + PACKAGE_WHITELIST_MODE_PROP + ": " + result, result != null && result.contains("Failed")); } private void removeUser(int userId) { private void removeUser(int userId) { try { try { mUm.removeUser(userId); mUm.removeUser(userId); Loading core/java/android/content/pm/PackageManagerInternal.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -307,6 +307,17 @@ public abstract class PackageManagerInternal { */ */ public abstract String getNameForUid(int uid); public abstract String getNameForUid(int uid); /** * Marks a package as installed (or not installed) for a given user. * * @param pkg the package whose installation is to be set * @param userId the user for whom to set it * @param installed the new installed state * @return true if the installed state changed as a result */ public abstract boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId, boolean installed); /** /** * Request to perform the second phase of ephemeral resolution. * Request to perform the second phase of ephemeral resolution. * @param responseObj The response of the first phase of ephemeral resolution * @param responseObj The response of the first phase of ephemeral resolution Loading core/java/android/content/pm/UserInfo.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -125,6 +125,13 @@ public class UserInfo implements Parcelable { */ */ public static final int FLAG_SYSTEM = 0x00000800; public static final int FLAG_SYSTEM = 0x00000800; /** * Indicates that this user is some sort of profile. Right now, the only profile type is * {@link #FLAG_MANAGED_PROFILE}, but this can include other types of profiles too if any * are created in the future. This is therefore not a flag, but an OR of several flags. */ public static final int PROFILE_FLAGS_MASK = FLAG_MANAGED_PROFILE; /** /** * @hide * @hide */ */ Loading core/java/com/android/server/SystemConfig.java +101 −1 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.Xml; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; import libcore.io.IoUtils; Loading @@ -50,6 +51,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Set; /** /** * Loads global system configuration info. * Loads global system configuration info. Loading Loading @@ -209,6 +211,10 @@ public class SystemConfig { private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); // Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService(). private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>(); private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>(); public static SystemConfig getInstance() { public static SystemConfig getInstance() { if (!isSystemProcess()) { if (!isSystemProcess()) { Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " Loading Loading @@ -359,7 +365,48 @@ public class SystemConfig { return mBugreportWhitelistedPackages; return mBugreportWhitelistedPackages; } } /** * Gets map of packagesNames to userTypes, dictating on which user types each package should be * initially installed, and then removes this map from SystemConfig. * Called by UserManagerService when it is constructed. */ public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeWhitelist() { ArrayMap<String, Set<String>> r = mPackageToUserTypeWhitelist; mPackageToUserTypeWhitelist = new ArrayMap<>(0); return r; } /** * Gets map of packagesNames to userTypes, dictating on which user types each package should NOT * be initially installed, even if they are whitelisted, and then removes this map from * SystemConfig. * Called by UserManagerService when it is constructed. */ public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeBlacklist() { ArrayMap<String, Set<String>> r = mPackageToUserTypeBlacklist; mPackageToUserTypeBlacklist = new ArrayMap<>(0); return r; } /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. */ @VisibleForTesting protected SystemConfig(boolean readPermissions) { if (readPermissions) { Slog.w(TAG, "Constructing a test SystemConfig"); readAllPermissions(); } else { Slog.w(TAG, "Constructing an empty test SystemConfig"); } } SystemConfig() { SystemConfig() { readAllPermissions(); } private void readAllPermissions() { // Read configuration from system // Read configuration from system readPermissions(Environment.buildPath( readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); Loading Loading @@ -419,7 +466,8 @@ public class SystemConfig { Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); } } void readPermissions(File libraryDir, int permissionFlag) { @VisibleForTesting public void readPermissions(File libraryDir, int permissionFlag) { // Read permissions from given directory. // Read permissions from given directory. if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (permissionFlag == ALLOW_ALL) { if (permissionFlag == ALLOW_ALL) { Loading Loading @@ -954,6 +1002,11 @@ public class SystemConfig { } } XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser); } break; } break; case "install-in-user-type": { // NB: We allow any directory permission to declare install-in-user-type. readInstallInUserType(parser, mPackageToUserTypeWhitelist, mPackageToUserTypeBlacklist); } break; default: { default: { Slog.w(TAG, "Tag " + name + " is unknown in " Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); + permFile + " at " + parser.getPositionDescription()); Loading Loading @@ -1091,6 +1144,53 @@ public class SystemConfig { } } } } private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) throws IOException, XmlPullParserException { final String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "package is required for <install-in-user-type> in " + parser.getPositionDescription()); return; } Set<String> userTypesYes = doInstallMap.get(packageName); Set<String> userTypesNo = nonInstallMap.get(packageName); final int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { final String name = parser.getName(); if ("install-in".equals(name)) { final String userType = parser.getAttributeValue(null, "user-type"); if (TextUtils.isEmpty(userType)) { Slog.w(TAG, "user-type is required for <install-in-user-type> in " + parser.getPositionDescription()); continue; } if (userTypesYes == null) { userTypesYes = new ArraySet<>(); doInstallMap.put(packageName, userTypesYes); } userTypesYes.add(userType); } else if ("do-not-install-in".equals(name)) { final String userType = parser.getAttributeValue(null, "user-type"); if (TextUtils.isEmpty(userType)) { Slog.w(TAG, "user-type is required for <install-in-user-type> in " + parser.getPositionDescription()); continue; } if (userTypesNo == null) { userTypesNo = new ArraySet<>(); nonInstallMap.put(packageName, userTypesNo); } userTypesNo.add(userType); } else { Slog.w(TAG, "unrecognized tag in <install-in-user-type> in " + parser.getPositionDescription()); } } } void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { final String packageName = parser.getAttributeValue(null, "package"); final String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { if (TextUtils.isEmpty(packageName)) { Loading Loading
apct-tests/perftests/multiuser/AndroidManifest.xml +1 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application> <application> <uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" /> Loading
apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +77 −0 Original line number Original line Diff line number Diff line Loading @@ -38,8 +38,10 @@ import android.os.Bundle; import android.os.IBinder; import android.os.IBinder; import android.os.IProgressListener; import android.os.IProgressListener; import android.os.RemoteException; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManager; import android.perftests.utils.ShellHelper; import android.util.Log; import android.util.Log; import android.view.WindowManagerGlobal; import android.view.WindowManagerGlobal; Loading Loading @@ -85,6 +87,14 @@ public class UserLifecycleTests { private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp"; private static final String DUMMY_PACKAGE_NAME = "perftests.multiuser.apps.dummyapp"; // Copy of UserSystemPackageInstaller whitelist mode constants. private static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode"; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100; private static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1; private UserManager mUm; private UserManager mUm; private ActivityManager mAm; private ActivityManager mAm; private IActivityManager mIam; private IActivityManager mIam; Loading Loading @@ -442,6 +452,55 @@ public class UserLifecycleTests { } } } } // TODO: This is just a POC. Do this properly and add more. /** Tests starting (unlocking) a newly-created profile using the user-type-pkg-whitelist. */ @Test public void managedProfileUnlock_usingWhitelist() throws Exception { assumeTrue(mHasManagedUserFeature); final int origMode = getUserTypePackageWhitelistMode(); setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE | USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST); try { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int userId = createManagedProfile(); mRunner.resumeTiming(); startUserInBackground(userId); mRunner.pauseTiming(); removeUser(userId); mRunner.resumeTiming(); } } finally { setUserTypePackageWhitelistMode(origMode); } } /** Tests starting (unlocking) a newly-created profile NOT using the user-type-pkg-whitelist. */ @Test public void managedProfileUnlock_notUsingWhitelist() throws Exception { assumeTrue(mHasManagedUserFeature); final int origMode = getUserTypePackageWhitelistMode(); setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE); try { while (mRunner.keepRunning()) { mRunner.pauseTiming(); final int userId = createManagedProfile(); mRunner.resumeTiming(); startUserInBackground(userId); mRunner.pauseTiming(); removeUser(userId); mRunner.resumeTiming(); } } finally { setUserTypePackageWhitelistMode(origMode); } } /** Creates a new user, returning its userId. */ /** Creates a new user, returning its userId. */ private int createUserNoFlags() { private int createUserNoFlags() { return createUserWithFlags(/* flags= */ 0); return createUserWithFlags(/* flags= */ 0); Loading @@ -458,6 +517,10 @@ public class UserLifecycleTests { private int createManagedProfile() { private int createManagedProfile() { final UserInfo userInfo = mUm.createProfileForUser("TestProfile", final UserInfo userInfo = mUm.createProfileForUser("TestProfile", UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); if (userInfo == null) { throw new IllegalStateException("Creating managed profile failed. Most likely there is " + "already a pre-existing profile on the device."); } mUsersToRemove.add(userInfo.id); mUsersToRemove.add(userInfo.id); return userInfo.id; return userInfo.id; } } Loading Loading @@ -627,6 +690,20 @@ public class UserLifecycleTests { } } } } /** Gets the PACKAGE_WHITELIST_MODE_PROP System Property. */ private int getUserTypePackageWhitelistMode() { return SystemProperties.getInt(PACKAGE_WHITELIST_MODE_PROP, USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT); } /** Sets the PACKAGE_WHITELIST_MODE_PROP System Property to the given value. */ private void setUserTypePackageWhitelistMode(int mode) { String result = ShellHelper.runShellCommand( String.format("setprop %s %d", PACKAGE_WHITELIST_MODE_PROP, mode)); attestFalse("Failed to set sysprop " + PACKAGE_WHITELIST_MODE_PROP + ": " + result, result != null && result.contains("Failed")); } private void removeUser(int userId) { private void removeUser(int userId) { try { try { mUm.removeUser(userId); mUm.removeUser(userId); Loading
core/java/android/content/pm/PackageManagerInternal.java +11 −0 Original line number Original line Diff line number Diff line Loading @@ -307,6 +307,17 @@ public abstract class PackageManagerInternal { */ */ public abstract String getNameForUid(int uid); public abstract String getNameForUid(int uid); /** * Marks a package as installed (or not installed) for a given user. * * @param pkg the package whose installation is to be set * @param userId the user for whom to set it * @param installed the new installed state * @return true if the installed state changed as a result */ public abstract boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId, boolean installed); /** /** * Request to perform the second phase of ephemeral resolution. * Request to perform the second phase of ephemeral resolution. * @param responseObj The response of the first phase of ephemeral resolution * @param responseObj The response of the first phase of ephemeral resolution Loading
core/java/android/content/pm/UserInfo.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -125,6 +125,13 @@ public class UserInfo implements Parcelable { */ */ public static final int FLAG_SYSTEM = 0x00000800; public static final int FLAG_SYSTEM = 0x00000800; /** * Indicates that this user is some sort of profile. Right now, the only profile type is * {@link #FLAG_MANAGED_PROFILE}, but this can include other types of profiles too if any * are created in the future. This is therefore not a flag, but an OR of several flags. */ public static final int PROFILE_FLAGS_MASK = FLAG_MANAGED_PROFILE; /** /** * @hide * @hide */ */ Loading
core/java/com/android/server/SystemConfig.java +101 −1 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseArray; import android.util.Xml; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils; import libcore.io.IoUtils; import libcore.io.IoUtils; Loading @@ -50,6 +51,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Set; /** /** * Loads global system configuration info. * Loads global system configuration info. Loading Loading @@ -209,6 +211,10 @@ public class SystemConfig { private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); // Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService(). private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>(); private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>(); public static SystemConfig getInstance() { public static SystemConfig getInstance() { if (!isSystemProcess()) { if (!isSystemProcess()) { Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " Loading Loading @@ -359,7 +365,48 @@ public class SystemConfig { return mBugreportWhitelistedPackages; return mBugreportWhitelistedPackages; } } /** * Gets map of packagesNames to userTypes, dictating on which user types each package should be * initially installed, and then removes this map from SystemConfig. * Called by UserManagerService when it is constructed. */ public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeWhitelist() { ArrayMap<String, Set<String>> r = mPackageToUserTypeWhitelist; mPackageToUserTypeWhitelist = new ArrayMap<>(0); return r; } /** * Gets map of packagesNames to userTypes, dictating on which user types each package should NOT * be initially installed, even if they are whitelisted, and then removes this map from * SystemConfig. * Called by UserManagerService when it is constructed. */ public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeBlacklist() { ArrayMap<String, Set<String>> r = mPackageToUserTypeBlacklist; mPackageToUserTypeBlacklist = new ArrayMap<>(0); return r; } /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. */ @VisibleForTesting protected SystemConfig(boolean readPermissions) { if (readPermissions) { Slog.w(TAG, "Constructing a test SystemConfig"); readAllPermissions(); } else { Slog.w(TAG, "Constructing an empty test SystemConfig"); } } SystemConfig() { SystemConfig() { readAllPermissions(); } private void readAllPermissions() { // Read configuration from system // Read configuration from system readPermissions(Environment.buildPath( readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); Loading Loading @@ -419,7 +466,8 @@ public class SystemConfig { Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); } } void readPermissions(File libraryDir, int permissionFlag) { @VisibleForTesting public void readPermissions(File libraryDir, int permissionFlag) { // Read permissions from given directory. // Read permissions from given directory. if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (permissionFlag == ALLOW_ALL) { if (permissionFlag == ALLOW_ALL) { Loading Loading @@ -954,6 +1002,11 @@ public class SystemConfig { } } XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser); } break; } break; case "install-in-user-type": { // NB: We allow any directory permission to declare install-in-user-type. readInstallInUserType(parser, mPackageToUserTypeWhitelist, mPackageToUserTypeBlacklist); } break; default: { default: { Slog.w(TAG, "Tag " + name + " is unknown in " Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); + permFile + " at " + parser.getPositionDescription()); Loading Loading @@ -1091,6 +1144,53 @@ public class SystemConfig { } } } } private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) throws IOException, XmlPullParserException { final String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "package is required for <install-in-user-type> in " + parser.getPositionDescription()); return; } Set<String> userTypesYes = doInstallMap.get(packageName); Set<String> userTypesNo = nonInstallMap.get(packageName); final int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { final String name = parser.getName(); if ("install-in".equals(name)) { final String userType = parser.getAttributeValue(null, "user-type"); if (TextUtils.isEmpty(userType)) { Slog.w(TAG, "user-type is required for <install-in-user-type> in " + parser.getPositionDescription()); continue; } if (userTypesYes == null) { userTypesYes = new ArraySet<>(); doInstallMap.put(packageName, userTypesYes); } userTypesYes.add(userType); } else if ("do-not-install-in".equals(name)) { final String userType = parser.getAttributeValue(null, "user-type"); if (TextUtils.isEmpty(userType)) { Slog.w(TAG, "user-type is required for <install-in-user-type> in " + parser.getPositionDescription()); continue; } if (userTypesNo == null) { userTypesNo = new ArraySet<>(); nonInstallMap.put(packageName, userTypesNo); } userTypesNo.add(userType); } else { Slog.w(TAG, "unrecognized tag in <install-in-user-type> in " + parser.getPositionDescription()); } } } void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { final String packageName = parser.getAttributeValue(null, "package"); final String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { if (TextUtils.isEmpty(packageName)) { Loading