Loading core/java/android/app/admin/DevicePolicyManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -5730,4 +5730,32 @@ public class DevicePolicyManager { return false; } } /** * @hide * Returns whether the uninstall for {@code packageName} for the current user is in queue * to be started * @param packageName the package to check for * @return whether the uninstall intent for {@code packageName} is pending */ public boolean isUninstallInQueue(String packageName) { try { return mService.isUninstallInQueue(packageName); } catch (RemoteException re) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); return false; } } /** * @hide * @param packageName the package containing active DAs to be uninstalled */ public void uninstallPackageWithActiveAdmins(String packageName) { try { mService.uninstallPackageWithActiveAdmins(packageName); } catch (RemoteException re) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); } } } core/java/android/app/admin/IDevicePolicyManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -293,4 +293,7 @@ interface IDevicePolicyManager { boolean getDeviceLoggingEnabled(in ComponentName admin); ParceledListSlice retrieveDeviceLogs(in ComponentName admin); ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin); boolean isUninstallInQueue(String packageName); void uninstallPackageWithActiveAdmins(String packageName); } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +140 −19 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; Loading Loading @@ -274,6 +275,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int PROFILE_KEYGUARD_FEATURES = PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE; private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000; final Context mContext; final Injector mInjector; final IPackageManager mIPackageManager; Loading @@ -281,6 +284,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final UserManagerInternal mUserManagerInternal; private final LockPatternUtils mLockPatternUtils; /** * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p * is requested for user u. */ private final Set<Pair<String, Integer>> mPackagesToRemove = new ArraySet<Pair<String, Integer>>(); final LocalService mLocalService; // Stores and loads state on device and profile owners. Loading Loading @@ -2015,35 +2025,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { getUserData(userHandle).mRemovingAdmins.add(adminReceiver); sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { synchronized (DevicePolicyManagerService.this) { int userHandle = admin.getUserHandle().getIdentifier(); DevicePolicyData policy = getUserData(userHandle); boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); validatePasswordOwnerLocked(policy); if (doProxyCleanup) { resetGlobalProxyLocked(getUserData(userHandle)); } saveSettingsLocked(userHandle); updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); } // The removed admin might have disabled camera, so update user // restrictions. pushUserRestrictions(userHandle); removeAdminArtifacts(adminReceiver, userHandle); removePackageIfRequired(adminReceiver.getPackageName(), userHandle); } }); } } public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle, boolean throwForMissiongPermission) { if (!mHasFeature) { Loading Loading @@ -8465,4 +8459,131 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs(); return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null; } private void enforceCanManageDeviceAdmin() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS, null); } @Override public boolean isUninstallInQueue(final String packageName) { enforceCanManageDeviceAdmin(); final int userId = mInjector.userHandleGetCallingUserId(); Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { return mPackagesToRemove.contains(packageUserPair); } } @Override public void uninstallPackageWithActiveAdmins(final String packageName) { enforceCanManageDeviceAdmin(); Preconditions.checkArgument(!TextUtils.isEmpty(packageName)); final int userId = mInjector.userHandleGetCallingUserId(); final ComponentName profileOwner = getProfileOwner(userId); if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) { throw new IllegalArgumentException("Cannot uninstall a package with a profile owner"); } final ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false); if (getDeviceOwnerUserId() == userId && deviceOwner != null && packageName.equals(deviceOwner.getPackageName())) { throw new IllegalArgumentException("Cannot uninstall a package with a device owner"); } final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { mPackagesToRemove.add(packageUserPair); } final List<ComponentName> activeAdminsList = getActiveAdmins(userId); if (activeAdminsList == null || activeAdminsList.size() == 0) { startUninstallIntent(packageName, userId); return; } for (ComponentName activeAdmin : activeAdminsList) { if (packageName.equals(activeAdmin.getPackageName())) { removeActiveAdmin(activeAdmin, userId); } } mHandler.postDelayed(new Runnable() { @Override public void run() { for (ComponentName activeAdmin : activeAdminsList) { removeAdminArtifacts(activeAdmin, userId); } startUninstallIntent(packageName, userId); } }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway. } private void removePackageIfRequired(final String packageName, final int userId) { if (!packageHasActiveAdmins(packageName, userId)) { // Will not do anything if uninstall was not requested or was already started. startUninstallIntent(packageName, userId); } } private void startUninstallIntent(final String packageName, final int userId) { final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { if (!mPackagesToRemove.contains(packageUserPair)) { // Do nothing if uninstall was not requested or was already started. return; } mPackagesToRemove.remove(packageUserPair); } try { if (mInjector.getIPackageManager().getPackageInfo(packageName, 0, userId) == null) { // Package does not exist. Nothing to do. return; } } catch (RemoteException re) { Log.e(LOG_TAG, "Failure talking to PackageManager while getting package info"); } try { // force stop the package before uninstalling mInjector.getIActivityManager().forceStopPackage(packageName, userId); } catch (RemoteException re) { Log.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package"); } final Uri packageURI = Uri.parse("package:" + packageName); final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI); uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId)); } /** * Removes the admin from the policy. Ideally called after the admin's * {@link DeviceAdminReceiver#onDisabled(Context, Intent)} has been successfully completed. * * @param adminReceiver The admin to remove * @param userHandle The user for which this admin has to be removed. */ private void removeAdminArtifacts(final ComponentName adminReceiver, final int userHandle) { synchronized (this) { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin == null) { return; } final DevicePolicyData policy = getUserData(userHandle); final boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); validatePasswordOwnerLocked(policy); if (doProxyCleanup) { resetGlobalProxyLocked(policy); } saveSettingsLocked(userHandle); updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); } // The removed admin might have disabled camera, so update user // restrictions. pushUserRestrictions(userHandle); } } Loading
core/java/android/app/admin/DevicePolicyManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -5730,4 +5730,32 @@ public class DevicePolicyManager { return false; } } /** * @hide * Returns whether the uninstall for {@code packageName} for the current user is in queue * to be started * @param packageName the package to check for * @return whether the uninstall intent for {@code packageName} is pending */ public boolean isUninstallInQueue(String packageName) { try { return mService.isUninstallInQueue(packageName); } catch (RemoteException re) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); return false; } } /** * @hide * @param packageName the package containing active DAs to be uninstalled */ public void uninstallPackageWithActiveAdmins(String packageName) { try { mService.uninstallPackageWithActiveAdmins(packageName); } catch (RemoteException re) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); } } }
core/java/android/app/admin/IDevicePolicyManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -293,4 +293,7 @@ interface IDevicePolicyManager { boolean getDeviceLoggingEnabled(in ComponentName admin); ParceledListSlice retrieveDeviceLogs(in ComponentName admin); ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin); boolean isUninstallInQueue(String packageName); void uninstallPackageWithActiveAdmins(String packageName); }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +140 −19 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; Loading Loading @@ -274,6 +275,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int PROFILE_KEYGUARD_FEATURES = PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE; private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000; final Context mContext; final Injector mInjector; final IPackageManager mIPackageManager; Loading @@ -281,6 +284,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final UserManagerInternal mUserManagerInternal; private final LockPatternUtils mLockPatternUtils; /** * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p * is requested for user u. */ private final Set<Pair<String, Integer>> mPackagesToRemove = new ArraySet<Pair<String, Integer>>(); final LocalService mLocalService; // Stores and loads state on device and profile owners. Loading Loading @@ -2015,35 +2025,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { getUserData(userHandle).mRemovingAdmins.add(adminReceiver); sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { synchronized (DevicePolicyManagerService.this) { int userHandle = admin.getUserHandle().getIdentifier(); DevicePolicyData policy = getUserData(userHandle); boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); validatePasswordOwnerLocked(policy); if (doProxyCleanup) { resetGlobalProxyLocked(getUserData(userHandle)); } saveSettingsLocked(userHandle); updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); } // The removed admin might have disabled camera, so update user // restrictions. pushUserRestrictions(userHandle); removeAdminArtifacts(adminReceiver, userHandle); removePackageIfRequired(adminReceiver.getPackageName(), userHandle); } }); } } public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle, boolean throwForMissiongPermission) { if (!mHasFeature) { Loading Loading @@ -8465,4 +8459,131 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs(); return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null; } private void enforceCanManageDeviceAdmin() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS, null); } @Override public boolean isUninstallInQueue(final String packageName) { enforceCanManageDeviceAdmin(); final int userId = mInjector.userHandleGetCallingUserId(); Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { return mPackagesToRemove.contains(packageUserPair); } } @Override public void uninstallPackageWithActiveAdmins(final String packageName) { enforceCanManageDeviceAdmin(); Preconditions.checkArgument(!TextUtils.isEmpty(packageName)); final int userId = mInjector.userHandleGetCallingUserId(); final ComponentName profileOwner = getProfileOwner(userId); if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) { throw new IllegalArgumentException("Cannot uninstall a package with a profile owner"); } final ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false); if (getDeviceOwnerUserId() == userId && deviceOwner != null && packageName.equals(deviceOwner.getPackageName())) { throw new IllegalArgumentException("Cannot uninstall a package with a device owner"); } final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { mPackagesToRemove.add(packageUserPair); } final List<ComponentName> activeAdminsList = getActiveAdmins(userId); if (activeAdminsList == null || activeAdminsList.size() == 0) { startUninstallIntent(packageName, userId); return; } for (ComponentName activeAdmin : activeAdminsList) { if (packageName.equals(activeAdmin.getPackageName())) { removeActiveAdmin(activeAdmin, userId); } } mHandler.postDelayed(new Runnable() { @Override public void run() { for (ComponentName activeAdmin : activeAdminsList) { removeAdminArtifacts(activeAdmin, userId); } startUninstallIntent(packageName, userId); } }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway. } private void removePackageIfRequired(final String packageName, final int userId) { if (!packageHasActiveAdmins(packageName, userId)) { // Will not do anything if uninstall was not requested or was already started. startUninstallIntent(packageName, userId); } } private void startUninstallIntent(final String packageName, final int userId) { final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId); synchronized (this) { if (!mPackagesToRemove.contains(packageUserPair)) { // Do nothing if uninstall was not requested or was already started. return; } mPackagesToRemove.remove(packageUserPair); } try { if (mInjector.getIPackageManager().getPackageInfo(packageName, 0, userId) == null) { // Package does not exist. Nothing to do. return; } } catch (RemoteException re) { Log.e(LOG_TAG, "Failure talking to PackageManager while getting package info"); } try { // force stop the package before uninstalling mInjector.getIActivityManager().forceStopPackage(packageName, userId); } catch (RemoteException re) { Log.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package"); } final Uri packageURI = Uri.parse("package:" + packageName); final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI); uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId)); } /** * Removes the admin from the policy. Ideally called after the admin's * {@link DeviceAdminReceiver#onDisabled(Context, Intent)} has been successfully completed. * * @param adminReceiver The admin to remove * @param userHandle The user for which this admin has to be removed. */ private void removeAdminArtifacts(final ComponentName adminReceiver, final int userHandle) { synchronized (this) { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin == null) { return; } final DevicePolicyData policy = getUserData(userHandle); final boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); validatePasswordOwnerLocked(policy); if (doProxyCleanup) { resetGlobalProxyLocked(policy); } saveSettingsLocked(userHandle); updateMaximumTimeToLockLocked(userHandle); policy.mRemovingAdmins.remove(adminReceiver); } // The removed admin might have disabled camera, so update user // restrictions. pushUserRestrictions(userHandle); } }