Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 338c1d86 authored by Suprabh Shukla's avatar Suprabh Shukla Committed by Android (Google) Code Review
Browse files

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

parents db338c2e a2ae2238
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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);
}
+140 −19
Original line number Diff line number Diff line
@@ -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);
    }
}