Merge "Added an api to uninstall a packge with active DAs" into nyc-dev

This commit is contained in:
Suprabh Shukla
2016-02-10 22:47:59 +00:00
committed by Android (Google) Code Review
3 changed files with 171 additions and 19 deletions

View File

@@ -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);
}
}
}

View File

@@ -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);
}

View File

@@ -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;
@@ -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;
@@ -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.
@@ -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) {
@@ -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);
}
}