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

Commit 088d7aa9 authored by Robin Lee's avatar Robin Lee
Browse files

Exfiltrate cert code from DevicePolicyManager

The intent is for this not to cause any behaviour changes, just to
make it easier to see what is going on with the code.

Permissions are checked in DevicePolicyManagerService. All calls to
CertificateMonitor are privileged.

Test: runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Test: cts-tradefed run cts-dev --module CtsDevicePolicyManagerTestCases
Change-Id: I98224087315a62234732f08b53fe91884be86386
parent 2c68dadb
Loading
Loading
Loading
Loading
+232 −0
Original line number Diff line number Diff line
@@ -19,100 +19,175 @@ package com.android.server.devicepolicy;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
import android.util.Log;

import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.R;

import java.util.ArrayList;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Set;

public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> {
public class CertificateMonitor {
    protected static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
    protected static final int MONITORING_CERT_NOTIFICATION_ID = R.plurals.ssl_ca_cert_warning;

    private final DevicePolicyManagerService mService;
    private final DevicePolicyManagerService.Injector mInjector;
    private final Handler mHandler;

    public MonitoringCertNotificationTask(final DevicePolicyManagerService service,
            final DevicePolicyManagerService.Injector injector) {
        super();
    public CertificateMonitor(final DevicePolicyManagerService service,
            final DevicePolicyManagerService.Injector injector, final Handler handler) {
        mService = service;
        mInjector = injector;
        mHandler = handler;

        // Broadcast filter for changes to the trusted certificate store. Listens on the background
        // handler to avoid blocking time-critical tasks on the main handler thread.
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_STARTED);
        filter.addAction(Intent.ACTION_USER_UNLOCKED);
        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mInjector.mContext.registerReceiverAsUser(
                mRootCaReceiver, UserHandle.ALL, filter, null, mHandler);
    }

    @Override
    protected Void doInBackground(Integer... params) {
        int userHandle = params[0];
    public String installCaCert(final UserHandle userHandle, byte[] certBuffer) {
        // Convert certificate data from X509 format to PEM.
        byte[] pemCert;
        try {
            X509Certificate cert = parseCert(certBuffer);
            pemCert = Credentials.convertToPem(cert);
        } catch (CertificateException | IOException ce) {
            Log.e(LOG_TAG, "Problem converting cert", ce);
            return null;
        }

        if (userHandle == UserHandle.USER_ALL) {
            for (UserInfo userInfo : mInjector.getUserManager().getUsers(true)) {
                repostOrClearNotification(userInfo.getUserHandle());
        try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
            return keyChainConnection.getService().installCaCertificate(pemCert);
        } catch (RemoteException e) {
            Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
        } catch (InterruptedException e1) {
            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
            Thread.currentThread().interrupt();
        }
        } else {
            repostOrClearNotification(UserHandle.of(userHandle));
        return null;
    }

    public void uninstallCaCerts(final UserHandle userHandle, final String[] aliases) {
        try (KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(userHandle)) {
            for (int i = 0 ; i < aliases.length; i++) {
                keyChainConnection.getService().deleteCaCertificate(aliases[i]);
            }
        } catch (RemoteException e) {
            Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
        } catch (InterruptedException ie) {
            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
            Thread.currentThread().interrupt();
        }
    }

    public List<String> getInstalledCaCertificates(UserHandle userHandle)
            throws RemoteException, RuntimeException {
        try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
            return conn.getService().getUserCaAliases().getList();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } catch (AssertionError e) {
            throw new RuntimeException(e);
        }
    }

    public void onCertificateApprovalsChanged(int userId) {
        mHandler.post(() -> updateInstalledCertificates(UserHandle.of(userId)));
    }

    /**
     * Broadcast receiver for changes to the trusted certificate store.
     */
    private final BroadcastReceiver mRootCaReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (StorageManager.inCryptKeeperBounce()) {
                return;
            }
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
            updateInstalledCertificates(UserHandle.of(userId));
        }
    };

    private void repostOrClearNotification(UserHandle userHandle) {
    private void updateInstalledCertificates(final UserHandle userHandle) {
        if (!mInjector.getUserManager().isUserUnlocked(userHandle.getIdentifier())) {
            return;
        }

        // Call out to KeyChain to check for CAs which are waiting for approval.
        final int pendingCertificateCount;
        final List<String> installedCerts;
        try {
            pendingCertificateCount = mService.retainAcceptedCertificates(
                    userHandle, getInstalledCaCertificates(userHandle));
            installedCerts = getInstalledCaCertificates(userHandle);
        } catch (RemoteException | RuntimeException e) {
            Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e);
            return;
        }
        mService.onInstalledCertificatesChanged(userHandle, installedCerts);

        final int pendingCertificateCount =
                installedCerts.size() - mService.getAcceptedCaCertificates(userHandle).size();
        if (pendingCertificateCount != 0) {
            showNotification(userHandle, pendingCertificateCount);
            final Notification noti = buildNotification(userHandle, pendingCertificateCount);
            mInjector.getNotificationManager().notifyAsUser(
                    LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
        } else {
            mInjector.getNotificationManager().cancelAsUser(
                    LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, userHandle);
        }
    }

    private void showNotification(UserHandle userHandle, int pendingCertificateCount) {
        // Create a context for the target user.
    private Notification buildNotification(UserHandle userHandle, int pendingCertificateCount) {
        final Context userContext;
        try {
            userContext = mInjector.createContextAsUser(userHandle);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e);
            return;
            return null;
        }

        // Build and show a warning notification
        int smallIconId;
        String contentText;
        final Resources resources = mInjector.getResources();
        final int smallIconId;
        final String contentText;

        int parentUserId = userHandle.getIdentifier();
        Resources resources = mInjector.getResources();

        if (mService.getProfileOwner(userHandle.getIdentifier()) != null) {
            contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
                    mService.getProfileOwnerName(userHandle.getIdentifier()));
            smallIconId = R.drawable.stat_sys_certificate_info;
            parentUserId = mService.getProfileParentId(userHandle.getIdentifier());
        } else if (mService.getDeviceOwnerUserId() == userHandle.getIdentifier()) {
            final String ownerName = mService.getDeviceOwnerName();
            contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
                    mService.getDeviceOwnerName());
            smallIconId = R.drawable.stat_sys_certificate_info;
@@ -121,19 +196,24 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
            smallIconId = android.R.drawable.stat_sys_warning;
        }

        // Create an intent to launch an activity showing information about the certificate.
        Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
        dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        // TODO this next line is taken from original notification code in
        // {@link DevicePolicyManagerService} but not a very good way of doing it. Do it better.
        dialogIntent.setPackage("com.android.settings");
        dialogIntent.putExtra(Settings.EXTRA_NUMBER_OF_CERTIFICATES, pendingCertificateCount);
        dialogIntent.putExtra(Intent.EXTRA_USER_ID, userHandle.getIdentifier());
        PendingIntent notifyIntent = PendingIntent.getActivityAsUser(userContext, 0,

        // The intent should only be allowed to resolve to a system app.
        ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
                mInjector.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
        if (targetInfo != null) {
            dialogIntent.setComponent(targetInfo.getComponentName());
        }

        PendingIntent notifyIntent = mInjector.pendingIntentGetActivityAsUser(userContext, 0,
                dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
                UserHandle.of(parentUserId));

        final Notification noti =
                new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
        return new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
                .setSmallIcon(smallIconId)
                .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
                        pendingCertificateCount))
@@ -142,20 +222,11 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
                .setShowWhen(false)
                .setColor(R.color.system_notification_accent_color)
                .build();

        mInjector.getNotificationManager().notifyAsUser(
                LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
    }

    private List<String> getInstalledCaCertificates(UserHandle userHandle)
            throws RemoteException, RuntimeException {
        try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
            return conn.getService().getUserCaAliases().getList();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } catch (AssertionError e) {
            throw new RuntimeException(e);
        }
    private static X509Certificate parseCert(byte[] certBuffer) throws CertificateException {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
                certBuffer));
    }
}
+55 −114
Original line number Diff line number Diff line
@@ -114,7 +114,6 @@ import android.net.Uri;
import android.net.metrics.IpConnectivityLog;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -184,7 +183,6 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -193,9 +191,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
@@ -398,6 +393,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     */
    boolean mIsWatch;

    private final CertificateMonitor mCertificateMonitor;
    private final SecurityLogMonitor mSecurityLogMonitor;
    private NetworkLogger mNetworkLogger;

@@ -530,19 +526,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    final Handler mHandler;
    final Handler mBackgroundHandler;

    /** Listens on any device, even when mHasFeature == false. */
    final BroadcastReceiver mRootCaReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (StorageManager.inCryptKeeperBounce()) {
                return;
            }
            final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId());
            new MonitoringCertNotificationTask(DevicePolicyManagerService.this, mInjector)
                    .execute(userHandle);
        }
    };

    /** Listens only if mHasFeature == true. */
    final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
@@ -630,25 +613,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
            } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) {
                clearWipeProfileNotification();
            } else if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) {
                mBackgroundHandler.post(() ->  {
                    try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                            UserHandle.of(userHandle))) {
                        final List<String> caCerts =
                                keyChainConnection.getService().getUserCaAliases().getList();
                        synchronized (DevicePolicyManagerService.this) {
                            if (getUserData(userHandle).mOwnerInstalledCaCerts
                                    .retainAll(caCerts)) {
                                saveSettingsLocked(userHandle);
                            }
                        }
                    } catch (InterruptedException e) {
                        Slog.w(LOG_TAG, "error talking to IKeyChainService", e);
                        Thread.currentThread().interrupt();
                    } catch (RemoteException e) {
                        Slog.w(LOG_TAG, "error talking to IKeyChainService", e);
                    }
                });
            }
        }

@@ -1527,7 +1491,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    @VisibleForTesting
    static class Injector {

        private final Context mContext;
        public final Context mContext;

        Injector(Context context) {
            mContext = context;
@@ -1720,6 +1684,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            return "/data/system/";
        }

        PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
                @NonNull Intent intent, int flags, Bundle options, UserHandle user) {
            return PendingIntent.getActivityAsUser(
                    context, requestCode, intent, flags, options, user);
        }

        void registerContentObserver(Uri uri, boolean notifyForDescendents,
                ContentObserver observer, int userHandle) {
            mContext.getContentResolver().registerContentObserver(uri, notifyForDescendents,
@@ -1810,6 +1780,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        mLocalService = new LocalService();
        mLockPatternUtils = injector.newLockPatternUtils();

        // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false?
        mSecurityLogMonitor = new SecurityLogMonitor(this);

        mHasFeature = mInjector.getPackageManager()
@@ -1818,27 +1789,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                .hasSystemFeature(PackageManager.FEATURE_WATCH);
        mBackgroundHandler = BackgroundThread.getHandler();

        // Broadcast filter for changes to the trusted certificate store. These changes get a
        // separate intent filter so we can listen to them even when device_admin is off.
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_STARTED);
        filter.addAction(Intent.ACTION_USER_UNLOCKED);
        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiverAsUser(mRootCaReceiver, UserHandle.ALL, filter, null, mHandler);
        // Needed when mHasFeature == false, because it controls the certificate warning text.
        mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);

        if (!mHasFeature) {
            // Skip the rest of the initialization
            return;
        }

        filter = new IntentFilter();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
        filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_REMOVED);
        filter.addAction(Intent.ACTION_USER_STARTED);
        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
        filter = new IntentFilter();
@@ -3083,33 +3047,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    /**
     * Remove deleted CA certificates from the "approved" list for a particular user, counting
     * the number still remaining to approve.
     * Clean up internal state when the set of installed trusted CA certificates changes.
     *
     * @param userHandle user to check for. This must be a real user and not, for example,
     *        {@link UserHandle#ALL}.
     * @param installedCertificates the full set of certificate authorities currently installed for
     *        {@param userHandle}. After calling this function, {@code mAcceptedCaCertificates} will
     *        correspond to some subset of this.
     *
     * @return number of certificates yet to be approved by {@param userHandle}.
     */
    protected synchronized int retainAcceptedCertificates(final UserHandle userHandle,
    protected void onInstalledCertificatesChanged(final UserHandle userHandle,
            final @NonNull Collection<String> installedCertificates) {
        if (!mHasFeature) {
            return;
        }
        enforceManageUsers();

        if (!mHasFeature) {
            return installedCertificates.size();
        } else {
        synchronized (this) {
            final DevicePolicyData policy = getUserData(userHandle.getIdentifier());

            // Remove deleted certificates. Flush xml if necessary.
            if (policy.mAcceptedCaCertificates.retainAll(installedCertificates)) {
            boolean changed = false;
            changed |= policy.mAcceptedCaCertificates.retainAll(installedCertificates);
            changed |= policy.mOwnerInstalledCaCerts.retainAll(installedCertificates);
            if (changed) {
                saveSettingsLocked(userHandle.getIdentifier());
            }
        }
    }

            // Trim approved certificates from the count.
            return installedCertificates.size() - policy.mAcceptedCaCertificates.size();
    /**
     * Internal method used by {@link CertificateMonitor}.
     */
    protected Set<String> getAcceptedCaCertificates(final UserHandle userHandle) {
        if (!mHasFeature) {
            return Collections.<String> emptySet();
        }
        synchronized (this) {
            final DevicePolicyData policy = getUserData(userHandle.getIdentifier());
            return policy.mAcceptedCaCertificates;
        }
    }

@@ -4690,7 +4664,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            }
            saveSettingsLocked(userId);
        }
        new MonitoringCertNotificationTask(this, mInjector).execute(userId);
        mCertificateMonitor.onCertificateApprovalsChanged(userId);
        return true;
    }

@@ -4713,8 +4687,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                    getUserData(userInfo.id).mAcceptedCaCertificates.clear();
                    saveSettingsLocked(userInfo.id);
                }

                new MonitoringCertNotificationTask(this, mInjector).execute(userInfo.id);
                mCertificateMonitor.onCertificateApprovalsChanged(userId);
            }
        }
    }
@@ -4722,79 +4695,47 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    @Override
    public boolean installCaCert(ComponentName admin, String callerPackage, byte[] certBuffer)
            throws RemoteException {
        enforceCanManageCaCerts(admin, callerPackage);

        byte[] pemCert;
        try {
            X509Certificate cert = parseCert(certBuffer);
            pemCert = Credentials.convertToPem(cert);
        } catch (CertificateException ce) {
            Log.e(LOG_TAG, "Problem converting cert", ce);
            return false;
        } catch (IOException ioe) {
            Log.e(LOG_TAG, "Problem reading cert", ioe);
        if (!mHasFeature) {
            return false;
        }
        enforceCanManageCaCerts(admin, callerPackage);

        final UserHandle userHandle = UserHandle.of(mInjector.userHandleGetCallingUserId());
        final String alias;

        final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
        final long id = mInjector.binderClearCallingIdentity();
        String alias = null;
        try {
            try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                    userHandle)) {
                alias = keyChainConnection.getService().installCaCertificate(pemCert);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
            alias = mCertificateMonitor.installCaCert(userHandle, certBuffer);
            if (alias == null) {
                Log.w(LOG_TAG, "Problem installing cert");
                return false;
            }
        } catch (InterruptedException e1) {
            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
            Thread.currentThread().interrupt();
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
        if (alias == null) {
            Log.w(LOG_TAG, "Problem installing cert");
        } else {

        synchronized (this) {
                final int userId = userHandle.getIdentifier();
                getUserData(userId).mOwnerInstalledCaCerts.add(alias);
                saveSettingsLocked(userId);
            getUserData(userHandle.getIdentifier()).mOwnerInstalledCaCerts.add(alias);
            saveSettingsLocked(userHandle.getIdentifier());
        }
        return true;
    }
        return false;
    }

    private static X509Certificate parseCert(byte[] certBuffer) throws CertificateException {
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
                certBuffer));
    }

    @Override
    public void uninstallCaCerts(ComponentName admin, String callerPackage, String[] aliases) {
        if (!mHasFeature) {
            return;
        }
        enforceCanManageCaCerts(admin, callerPackage);

        final int userId = mInjector.userHandleGetCallingUserId();
        final UserHandle userHandle = UserHandle.of(userId);
        final long id = mInjector.binderClearCallingIdentity();
        try {
            try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                    userHandle)) {
                for (int i = 0 ; i < aliases.length; i++) {
                    keyChainConnection.getService().deleteCaCertificate(aliases[i]);
                }
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
                return;
            }
        } catch (InterruptedException ie) {
            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
            Thread.currentThread().interrupt();
            return;
            mCertificateMonitor.uninstallCaCerts(UserHandle.of(userId), aliases);
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }

        synchronized (this) {
            if (getUserData(userId).mOwnerInstalledCaCerts.removeAll(Arrays.asList(aliases))) {
                saveSettingsLocked(userId);
+11 −0

File changed.

Preview size limit exceeded, changes collapsed.