Loading core/java/android/app/admin/DevicePolicyManager.java +42 −0 Original line number Diff line number Diff line Loading @@ -3615,6 +3615,48 @@ public class DevicePolicyManager { return null; } /** * Called by a device owner to get the list of apps to keep around as APKs even if no user has * currently installed it. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * * @return List of package names to keep cached. * @hide */ public List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getKeepUninstalledPackages(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } return null; } /** * Called by a device owner to set a list of apps to keep around as APKs even if no user has * currently installed it. * * <p>Please note that setting this policy does not imply that specified apps will be * automatically pre-cached.</p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageNames List of package names to keep cached. * @hide */ public void setKeepUninstalledPackages(@NonNull ComponentName admin, @NonNull List<String> packageNames) { if (mService != null) { try { mService.setKeepUninstalledPackages(admin, packageNames); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } } /** * Called by a device owner to create a user with the specified name. The UserHandle returned * by this method should not be persisted as user handles are recycled as users are removed and Loading core/java/android/app/admin/IDevicePolicyManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -231,4 +231,6 @@ interface IDevicePolicyManager { String permission, int grantState); int getPermissionGrantState(in ComponentName admin, String packageName, String permission); boolean isProvisioningAllowed(String action); void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList); List<String> getKeepUninstalledPackages(in ComponentName admin); } core/java/android/content/pm/PackageManagerInternal.java +8 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.content.pm; import android.annotation.NonNull; import java.util.List; /** * Package manager local system service interface. Loading Loading @@ -115,4 +115,11 @@ public abstract class PackageManagerInternal { */ public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId); /** * Sets a list of apps to keep in PM's internal data structures and as APKs even if no user has * currently installed it. The apps are not preloaded. * @param packageList List of package names to keep cached. */ public abstract void setKeepUninstalledPackages(List<String> packageList); } services/core/java/com/android/server/pm/PackageManagerService.java +70 −10 Original line number Diff line number Diff line Loading @@ -617,6 +617,9 @@ public class PackageManagerService extends IPackageManager.Stub { final DefaultPermissionGrantPolicy mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this); // List of packages names to keep cached, even if they are uninstalled for all users private List<String> mKeepUninstalledPackages; private static class IFVerificationParams { PackageParser.Package pkg; boolean replacing; Loading Loading @@ -13015,7 +13018,7 @@ public class PackageManagerService extends IPackageManager.Stub { final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0; final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId }; if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) { mContext.enforceCallingPermission( mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "deletePackage for user " + userId); } Loading Loading @@ -13090,6 +13093,10 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } private boolean shouldKeepUninstalledPackageLPr(String packageName) { return mKeepUninstalledPackages != null && mKeepUninstalledPackages.contains(packageName); } /** * This method is an internal method that could be get invoked either * to delete an installed package or to clean up a failed installation. Loading Loading @@ -13512,7 +13519,9 @@ public class PackageManagerService extends IPackageManager.Stub { false, // blockUninstall ps.readUserState(userId).domainVerificationStatus, 0); if (!isSystemApp(ps)) { if (ps.isAnyInstalled(sUserManager.getUserIds())) { // Do not uninstall the APK if an app should be cached boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName); if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) { // Other user still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. Loading Loading @@ -16686,7 +16695,12 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, "Checking package " + packageName); } boolean keep = false; boolean keep = shouldKeepUninstalledPackageLPr(packageName); if (keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Keeping package " + packageName + " - requested by DO"); } } else { for (int i = 0; i < users.length; i++) { if (users[i] != userHandle && ps.getInstalled(users[i])) { keep = true; Loading @@ -16697,6 +16711,7 @@ public class PackageManagerService extends IPackageManager.Stub { break; } } } if (!keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Removing package " + packageName); Loading Loading @@ -16896,6 +16911,23 @@ public class PackageManagerService extends IPackageManager.Stub { } } private void deletePackageIfUnusedLPr(final String packageName) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { return; } if (!ps.isAnyInstalled(sUserManager.getUserIds())) { // TODO Implement atomic delete if package is unused // It is currently possible that the package will be deleted even if it is installed // after this method returns. mHandler.post(new Runnable() { public void run() { deletePackageX(packageName, 0, PackageManager.DELETE_ALL_USERS); } }); } } /** * Check and throw if the given before/after packages would be considered a * downgrade. Loading Loading @@ -17133,6 +17165,34 @@ public class PackageManagerService extends IPackageManager.Stub { packageName, userId); } } @Override public void setKeepUninstalledPackages(final List<String> packageList) { Preconditions.checkNotNull(packageList); List<String> removedFromList = null; synchronized (mPackages) { if (mKeepUninstalledPackages != null) { final int packagesCount = mKeepUninstalledPackages.size(); for (int i = 0; i < packagesCount; i++) { String oldPackage = mKeepUninstalledPackages.get(i); if (packageList != null && packageList.contains(oldPackage)) { continue; } if (removedFromList == null) { removedFromList = new ArrayList<>(); } removedFromList.add(oldPackage); } } mKeepUninstalledPackages = new ArrayList<>(packageList); if (removedFromList != null) { final int removedCount = removedFromList.size(); for (int i = 0; i < removedCount; i++) { deletePackageIfUnusedLPr(removedFromList.get(i)); } } } } } @Override services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +64 −5 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; Loading Loading @@ -416,7 +417,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "cross-profile-widget-providers"; private static final String TAG_PROVIDER = "provider"; private static final String TAG_PACKAGE_LIST_ITEM = "item"; private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; final DeviceAdminInfo info; Loading Loading @@ -489,6 +490,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // allowed. List<String> permittedInputMethods; // List of package names to keep cached. List<String> keepUninstalledPackages; // TODO: review implementation decisions with frameworks team boolean specifiesGlobalProxy = false; String globalProxySpec = null; Loading Loading @@ -674,6 +678,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, permittedAccessiblityServices); writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); if (hasUserRestrictions()) { UserRestrictionsUtils.writeRestrictions( out, userRestrictions, TAG_USER_RESTRICTIONS); Loading Loading @@ -787,6 +792,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { permittedAccessiblityServices = readPackageList(parser, tag); } else if (TAG_PERMITTED_IMES.equals(tag)) { permittedInputMethods = readPackageList(parser, tag); } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { keepUninstalledPackages = readPackageList(parser, tag); } else if (TAG_USER_RESTRICTIONS.equals(tag)) { UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions()); } else { Loading Loading @@ -981,13 +988,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { pw.println(disabledKeyguardFeatures); pw.print(prefix); pw.print("crossProfileWidgetProviders="); pw.println(crossProfileWidgetProviders); if (!(permittedAccessiblityServices == null)) { if (permittedAccessiblityServices != null) { pw.print(prefix); pw.print("permittedAccessibilityServices="); pw.println(permittedAccessiblityServices.toString()); pw.println(permittedAccessiblityServices); } if (!(permittedInputMethods == null)) { if (permittedInputMethods != null) { pw.print(prefix); pw.print("permittedInputMethods="); pw.println(permittedInputMethods.toString()); pw.println(permittedInputMethods); } if (keepUninstalledPackages != null) { pw.print(prefix); pw.print("keepUninstalledPackages="); pw.println(keepUninstalledPackages); } pw.print(prefix); pw.println("userRestrictions:"); UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions); Loading Loading @@ -1068,6 +1079,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return LocalServices.getService(UserManagerInternal.class); } PackageManagerInternal getPackageManagerInternal() { return LocalServices.getService(PackageManagerInternal.class); } NotificationManager getNotificationManager() { return mContext.getSystemService(NotificationManager.class); } Loading Loading @@ -2101,6 +2116,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { new SetupContentObserver(mHandler).register(mContext.getContentResolver()); // Initialize the user setup state, to handle the upgrade case. updateUserSetupComplete(); List<String> packageList; synchronized (this) { packageList = getKeepUninstalledPackagesLocked(); } if (packageList != null) { mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList); } } private void ensureDeviceOwnerUserStarted() { Loading Loading @@ -4489,6 +4512,42 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } @Override public void setKeepUninstalledPackages(ComponentName who, List<String> packageList) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); Preconditions.checkNotNull(packageList, "packageList is null"); final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); admin.keepUninstalledPackages = packageList; saveSettingsLocked(userHandle); mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList); } } @Override public List<String> getKeepUninstalledPackages(ComponentName who) { Preconditions.checkNotNull(who, "ComponentName is null"); if (!mHasFeature) { return null; } // TODO In split system user mode, allow apps on user 0 to query the list synchronized (this) { // Check if this is the device owner who is calling getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); return getKeepUninstalledPackagesLocked(); } } private List<String> getKeepUninstalledPackagesLocked() { ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); return (deviceOwner != null) ? deviceOwner.keepUninstalledPackages : null; } @Override public boolean setDeviceOwner(ComponentName admin, String ownerName, int userId) { if (!mHasFeature) { Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +42 −0 Original line number Diff line number Diff line Loading @@ -3615,6 +3615,48 @@ public class DevicePolicyManager { return null; } /** * Called by a device owner to get the list of apps to keep around as APKs even if no user has * currently installed it. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * * @return List of package names to keep cached. * @hide */ public List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) { if (mService != null) { try { return mService.getKeepUninstalledPackages(admin); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } return null; } /** * Called by a device owner to set a list of apps to keep around as APKs even if no user has * currently installed it. * * <p>Please note that setting this policy does not imply that specified apps will be * automatically pre-cached.</p> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageNames List of package names to keep cached. * @hide */ public void setKeepUninstalledPackages(@NonNull ComponentName admin, @NonNull List<String> packageNames) { if (mService != null) { try { mService.setKeepUninstalledPackages(admin, packageNames); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } } /** * Called by a device owner to create a user with the specified name. The UserHandle returned * by this method should not be persisted as user handles are recycled as users are removed and Loading
core/java/android/app/admin/IDevicePolicyManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -231,4 +231,6 @@ interface IDevicePolicyManager { String permission, int grantState); int getPermissionGrantState(in ComponentName admin, String packageName, String permission); boolean isProvisioningAllowed(String action); void setKeepUninstalledPackages(in ComponentName admin,in List<String> packageList); List<String> getKeepUninstalledPackages(in ComponentName admin); }
core/java/android/content/pm/PackageManagerInternal.java +8 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.content.pm; import android.annotation.NonNull; import java.util.List; /** * Package manager local system service interface. Loading Loading @@ -115,4 +115,11 @@ public abstract class PackageManagerInternal { */ public abstract void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId); /** * Sets a list of apps to keep in PM's internal data structures and as APKs even if no user has * currently installed it. The apps are not preloaded. * @param packageList List of package names to keep cached. */ public abstract void setKeepUninstalledPackages(List<String> packageList); }
services/core/java/com/android/server/pm/PackageManagerService.java +70 −10 Original line number Diff line number Diff line Loading @@ -617,6 +617,9 @@ public class PackageManagerService extends IPackageManager.Stub { final DefaultPermissionGrantPolicy mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this); // List of packages names to keep cached, even if they are uninstalled for all users private List<String> mKeepUninstalledPackages; private static class IFVerificationParams { PackageParser.Package pkg; boolean replacing; Loading Loading @@ -13015,7 +13018,7 @@ public class PackageManagerService extends IPackageManager.Stub { final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0; final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId }; if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) { mContext.enforceCallingPermission( mContext.enforceCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "deletePackage for user " + userId); } Loading Loading @@ -13090,6 +13093,10 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } private boolean shouldKeepUninstalledPackageLPr(String packageName) { return mKeepUninstalledPackages != null && mKeepUninstalledPackages.contains(packageName); } /** * This method is an internal method that could be get invoked either * to delete an installed package or to clean up a failed installation. Loading Loading @@ -13512,7 +13519,9 @@ public class PackageManagerService extends IPackageManager.Stub { false, // blockUninstall ps.readUserState(userId).domainVerificationStatus, 0); if (!isSystemApp(ps)) { if (ps.isAnyInstalled(sUserManager.getUserIds())) { // Do not uninstall the APK if an app should be cached boolean keepUninstalledPackage = shouldKeepUninstalledPackageLPr(packageName); if (ps.isAnyInstalled(sUserManager.getUserIds()) || keepUninstalledPackage) { // Other user still have this package installed, so all // we need to do is clear this user's data and save that // it is uninstalled. Loading Loading @@ -16686,7 +16695,12 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, "Checking package " + packageName); } boolean keep = false; boolean keep = shouldKeepUninstalledPackageLPr(packageName); if (keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Keeping package " + packageName + " - requested by DO"); } } else { for (int i = 0; i < users.length; i++) { if (users[i] != userHandle && ps.getInstalled(users[i])) { keep = true; Loading @@ -16697,6 +16711,7 @@ public class PackageManagerService extends IPackageManager.Stub { break; } } } if (!keep) { if (DEBUG_CLEAN_APKS) { Slog.i(TAG, " Removing package " + packageName); Loading Loading @@ -16896,6 +16911,23 @@ public class PackageManagerService extends IPackageManager.Stub { } } private void deletePackageIfUnusedLPr(final String packageName) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps == null) { return; } if (!ps.isAnyInstalled(sUserManager.getUserIds())) { // TODO Implement atomic delete if package is unused // It is currently possible that the package will be deleted even if it is installed // after this method returns. mHandler.post(new Runnable() { public void run() { deletePackageX(packageName, 0, PackageManager.DELETE_ALL_USERS); } }); } } /** * Check and throw if the given before/after packages would be considered a * downgrade. Loading Loading @@ -17133,6 +17165,34 @@ public class PackageManagerService extends IPackageManager.Stub { packageName, userId); } } @Override public void setKeepUninstalledPackages(final List<String> packageList) { Preconditions.checkNotNull(packageList); List<String> removedFromList = null; synchronized (mPackages) { if (mKeepUninstalledPackages != null) { final int packagesCount = mKeepUninstalledPackages.size(); for (int i = 0; i < packagesCount; i++) { String oldPackage = mKeepUninstalledPackages.get(i); if (packageList != null && packageList.contains(oldPackage)) { continue; } if (removedFromList == null) { removedFromList = new ArrayList<>(); } removedFromList.add(oldPackage); } } mKeepUninstalledPackages = new ArrayList<>(packageList); if (removedFromList != null) { final int removedCount = removedFromList.size(); for (int i = 0; i < removedCount; i++) { deletePackageIfUnusedLPr(removedFromList.get(i)); } } } } } @Override
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +64 −5 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; Loading Loading @@ -416,7 +417,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "cross-profile-widget-providers"; private static final String TAG_PROVIDER = "provider"; private static final String TAG_PACKAGE_LIST_ITEM = "item"; private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; final DeviceAdminInfo info; Loading Loading @@ -489,6 +490,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // allowed. List<String> permittedInputMethods; // List of package names to keep cached. List<String> keepUninstalledPackages; // TODO: review implementation decisions with frameworks team boolean specifiesGlobalProxy = false; String globalProxySpec = null; Loading Loading @@ -674,6 +678,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, permittedAccessiblityServices); writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); if (hasUserRestrictions()) { UserRestrictionsUtils.writeRestrictions( out, userRestrictions, TAG_USER_RESTRICTIONS); Loading Loading @@ -787,6 +792,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { permittedAccessiblityServices = readPackageList(parser, tag); } else if (TAG_PERMITTED_IMES.equals(tag)) { permittedInputMethods = readPackageList(parser, tag); } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { keepUninstalledPackages = readPackageList(parser, tag); } else if (TAG_USER_RESTRICTIONS.equals(tag)) { UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions()); } else { Loading Loading @@ -981,13 +988,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { pw.println(disabledKeyguardFeatures); pw.print(prefix); pw.print("crossProfileWidgetProviders="); pw.println(crossProfileWidgetProviders); if (!(permittedAccessiblityServices == null)) { if (permittedAccessiblityServices != null) { pw.print(prefix); pw.print("permittedAccessibilityServices="); pw.println(permittedAccessiblityServices.toString()); pw.println(permittedAccessiblityServices); } if (!(permittedInputMethods == null)) { if (permittedInputMethods != null) { pw.print(prefix); pw.print("permittedInputMethods="); pw.println(permittedInputMethods.toString()); pw.println(permittedInputMethods); } if (keepUninstalledPackages != null) { pw.print(prefix); pw.print("keepUninstalledPackages="); pw.println(keepUninstalledPackages); } pw.print(prefix); pw.println("userRestrictions:"); UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", userRestrictions); Loading Loading @@ -1068,6 +1079,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return LocalServices.getService(UserManagerInternal.class); } PackageManagerInternal getPackageManagerInternal() { return LocalServices.getService(PackageManagerInternal.class); } NotificationManager getNotificationManager() { return mContext.getSystemService(NotificationManager.class); } Loading Loading @@ -2101,6 +2116,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { new SetupContentObserver(mHandler).register(mContext.getContentResolver()); // Initialize the user setup state, to handle the upgrade case. updateUserSetupComplete(); List<String> packageList; synchronized (this) { packageList = getKeepUninstalledPackagesLocked(); } if (packageList != null) { mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList); } } private void ensureDeviceOwnerUserStarted() { Loading Loading @@ -4489,6 +4512,42 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } @Override public void setKeepUninstalledPackages(ComponentName who, List<String> packageList) { if (!mHasFeature) { return; } Preconditions.checkNotNull(who, "ComponentName is null"); Preconditions.checkNotNull(packageList, "packageList is null"); final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); admin.keepUninstalledPackages = packageList; saveSettingsLocked(userHandle); mInjector.getPackageManagerInternal().setKeepUninstalledPackages(packageList); } } @Override public List<String> getKeepUninstalledPackages(ComponentName who) { Preconditions.checkNotNull(who, "ComponentName is null"); if (!mHasFeature) { return null; } // TODO In split system user mode, allow apps on user 0 to query the list synchronized (this) { // Check if this is the device owner who is calling getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); return getKeepUninstalledPackagesLocked(); } } private List<String> getKeepUninstalledPackagesLocked() { ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); return (deviceOwner != null) ? deviceOwner.keepUninstalledPackages : null; } @Override public boolean setDeviceOwner(ComponentName admin, String ownerName, int userId) { if (!mHasFeature) { Loading