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

Commit a3f54ce8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor RoleManagerService to use system API when possible."

parents 70a388e6 a5d44e88
Loading
Loading
Loading
Loading
+116 −81
Original line number Diff line number Diff line
@@ -18,13 +18,11 @@ package com.android.server.role;

import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.CheckResult;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.role.IOnRoleHoldersChangedListener;
import android.app.role.IRoleManager;
@@ -34,20 +32,22 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.Binder;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -57,11 +57,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ThrottledRunnable;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -71,7 +67,10 @@ import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -87,17 +86,18 @@ import java.util.concurrent.TimeoutException;
 * @see RoleManager
 */
public class RoleManagerService extends SystemService implements RoleUserState.Callback {

    private static final String LOG_TAG = RoleManagerService.class.getSimpleName();

    private static final boolean DEBUG = false;

    private static final long GRANT_DEFAULT_ROLES_INTERVAL_MILLIS = 1000;

    @NonNull
    private final UserManagerInternal mUserManagerInternal;
    @NonNull
    private final AppOpsManager mAppOpsManager;
    @NonNull
    private final PackageManagerInternal mPackageManagerInternal;
    @NonNull
    private final UserManagerInternal mUserManagerInternal;

    @NonNull
    private final Object mLock = new Object();
@@ -146,8 +146,9 @@ public class RoleManagerService extends SystemService implements RoleUserState.C

        RoleControllerManager.initializeRemoteServiceComponentName(context);

        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
        mAppOpsManager = context.getSystemService(AppOpsManager.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);

        LocalServices.addService(RoleManagerInternal.class, new Internal());

@@ -157,15 +158,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
    private void registerUserRemovedReceiver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
        getContext().registerReceiverAsUser(new BroadcastReceiver() {
        getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
            @Override
            public void onReceive(@NonNull Context context, @NonNull Intent intent) {
                if (TextUtils.equals(intent.getAction(), Intent.ACTION_USER_REMOVED)) {
                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                    int userId = intent.<UserHandle>getParcelableExtra(Intent.EXTRA_USER)
                            .getIdentifier();
                    onRemoveUser(userId);
                }
            }
        }, UserHandle.ALL, intentFilter, null, null);
        }, intentFilter, null, null);
    }

    @Override
@@ -178,7 +180,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        getContext().registerReceiverAsUser(new BroadcastReceiver() {
        getContext().registerReceiverForAllUsers(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int userId = UserHandle.getUserId(intent.getIntExtra(Intent.EXTRA_UID, -1));
@@ -193,12 +195,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                }
                maybeGrantDefaultRolesAsync(userId);
            }
        }, UserHandle.ALL, intentFilter, null, null);
        }, intentFilter, null, null);
    }

    @Override
    public void onUserStarting(@NonNull TargetUser user) {
        maybeGrantDefaultRolesSync(user.getUserIdentifier());
        maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
    }

    @MainThread
@@ -230,7 +232,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
    private AndroidFuture<Void> maybeGrantDefaultRolesInternal(@UserIdInt int userId) {
        RoleUserState userState = getOrCreateUserState(userId);
        String oldPackagesHash = userState.getPackagesHash();
        String newPackagesHash = computeComponentStateHash(userId);
        String newPackagesHash = computePackageStateHash(userId);
        if (Objects.equals(oldPackagesHash, newPackagesHash)) {
            if (DEBUG) {
                Slog.i(LOG_TAG, "Already granted default roles for packages hash "
@@ -282,35 +284,42 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
    }

    @Nullable
    private static String computeComponentStateHash(@UserIdInt int userId) {
        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
    private String computePackageStateHash(@UserIdInt int userId) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);

        pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> {
            out.write(pkg.getPackageName().getBytes());
            out.write(BitUtils.toBytes(pkg.getLongVersionCode()));
            out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId));
        mPackageManagerInternal.forEachInstalledPackage(pkg -> {
            try {
                dataOutputStream.writeUTF(pkg.getPackageName());
                dataOutputStream.writeLong(pkg.getLongVersionCode());
                dataOutputStream.writeInt(mPackageManagerInternal.getApplicationEnabledState(
                        pkg.getPackageName(), userId));

                ArraySet<String> enabledComponents =
                    pm.getEnabledComponents(pkg.getPackageName(), userId);
                        mPackageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId);
                int numComponents = CollectionUtils.size(enabledComponents);
            out.write(numComponents);
                dataOutputStream.writeInt(numComponents);
                for (int i = 0; i < numComponents; i++) {
                out.write(enabledComponents.valueAt(i).getBytes());
                    dataOutputStream.writeUTF(enabledComponents.valueAt(i));
                }

                ArraySet<String> disabledComponents =
                    pm.getDisabledComponents(pkg.getPackageName(), userId);
                        mPackageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId);
                numComponents = CollectionUtils.size(disabledComponents);
                for (int i = 0; i < numComponents; i++) {
                out.write(disabledComponents.valueAt(i).getBytes());
                    dataOutputStream.writeUTF(disabledComponents.valueAt(i));
                }

                for (Signature signature : pkg.getSigningDetails().signatures) {
                out.write(signature.toByteArray());
                    dataOutputStream.write(signature.toByteArray());
                }
            } catch (IOException e) {
                // Never happens for ByteArrayOutputStream and DataOutputStream.
                throw new AssertionError(e);
            }
        }), userId);
        }, userId);

        return PackageUtils.computeSha256Digest(out.toByteArray());
        return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray());
    }

    @NonNull
@@ -335,7 +344,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                try {
                    context = systemContext.createPackageContextAsUser(
                            systemContext.getPackageName(), 0, UserHandle.of(userId));
                } catch (NameNotFoundException e) {
                } catch (PackageManager.NameNotFoundException e) {
                    throw new RuntimeException(e);
                }
                controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
@@ -371,9 +380,11 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
        RoleUserState userState;
        synchronized (mLock) {
            mGrantDefaultRolesThrottledRunnables.remove(userId);
            listeners = mListeners.removeReturnOld(userId);
            listeners = mListeners.get(userId);
            mListeners.remove(userId);
            mControllers.remove(userId);
            userState = mUserStates.removeReturnOld(userId);
            userState = mUserStates.get(userId);
            mUserStates.remove(userId);
        }
        if (listeners != null) {
            listeners.kill();
@@ -455,7 +466,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return Collections.emptyList();
            }
            userId = handleIncomingUser(userId, false, "getRoleHoldersAsUser");
            enforceCrossUserPermission(userId, false, "getRoleHoldersAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                    "getRoleHoldersAsUser");

@@ -476,7 +487,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return;
            }
            userId = handleIncomingUser(userId, false, "addRoleHolderAsUser");
            enforceCrossUserPermission(userId, false, "addRoleHolderAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                    "addRoleHolderAsUser");

@@ -496,7 +507,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return;
            }
            userId = handleIncomingUser(userId, false, "removeRoleHolderAsUser");
            enforceCrossUserPermission(userId, false, "removeRoleHolderAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                    "removeRoleHolderAsUser");

@@ -516,7 +527,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return;
            }
            userId = handleIncomingUser(userId, false, "clearRoleHoldersAsUser");
            enforceCrossUserPermission(userId, false, "clearRoleHoldersAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                    "clearRoleHoldersAsUser");

@@ -533,7 +544,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return;
            }
            userId = handleIncomingUser(userId, true, "addOnRoleHoldersChangedListenerAsUser");
            enforceCrossUserPermission(userId, true, "addOnRoleHoldersChangedListenerAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                    "addOnRoleHoldersChangedListenerAsUser");

@@ -551,7 +562,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                Slog.e(LOG_TAG, "user " + userId + " does not exist");
                return;
            }
            userId = handleIncomingUser(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
            enforceCrossUserPermission(userId, true, "removeOnRoleHoldersChangedListenerAsUser");
            getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
                    "removeOnRoleHoldersChangedListenerAsUser");

@@ -572,7 +583,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C

            Objects.requireNonNull(roleNames, "roleNames cannot be null");

            int userId = UserHandle.getCallingUserId();
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            getOrCreateUserState(userId).setRoleNames(roleNames);
        }

@@ -586,7 +597,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");

            int userId = UserHandle.getCallingUserId();
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
        }

@@ -600,7 +611,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");

            int userId = UserHandle.getCallingUserId();
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
        }

@@ -612,23 +623,36 @@ public class RoleManagerService extends SystemService implements RoleUserState.C

            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");

            int userId = UserHandle.getCallingUserId();
            int userId = UserHandle.getUserId(Binder.getCallingUid());
            return getOrCreateUserState(userId).getHeldRoles(packageName);
        }

        @CheckResult
        private int handleIncomingUser(@UserIdInt int userId, boolean allowAll,
                @NonNull String name) {
            return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                    allowAll, true, name, null);
        private void enforceCrossUserPermission(@UserIdInt int userId, boolean allowAll,
                @NonNull String message) {
            final int callingUid = Binder.getCallingUid();
            final int callingUserId = UserHandle.getUserId(callingUid);
            if (userId == callingUserId) {
                return;
            }
            Preconditions.checkArgument(userId >= UserHandle.USER_SYSTEM
                    || (allowAll && userId == UserHandle.USER_ALL), "Invalid user " + userId);
            getContext().enforceCallingOrSelfPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
            if (callingUid == Process.SHELL_UID && userId >= UserHandle.USER_SYSTEM) {
                if (mUserManagerInternal.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
                        userId)) {
                    throw new SecurityException("Shell does not have permission to access user "
                            + userId);
                }
            }
        }

        @Override
        public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                @Nullable FileDescriptor err, @NonNull String[] args,
                @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) {
            new RoleManagerShellCommand(this).exec(this, in, out, err, args, callback,
                    resultReceiver);
        public int handleShellCommand(@NonNull ParcelFileDescriptor in,
                @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
                @NonNull String[] args) {
            return new RoleManagerShellCommand(this).exec(this, in.getFileDescriptor(),
                    out.getFileDescriptor(), err.getFileDescriptor(), args);
        }

        @Nullable
@@ -639,9 +663,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
                getContext().enforceCallingOrSelfPermission(
                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
            }
            final PackageManagerInternal packageManager = LocalServices.getService(
                    PackageManagerInternal.class);
            if (packageManager.getInstantAppPackageName(callingUid) != null) {
            if (mPackageManagerInternal.getInstantAppPackageName(callingUid) != null) {
                return null;
            }

@@ -659,7 +681,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
            final Context context = getContext();
            context.enforceCallingOrSelfPermission(
                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
            if (UserHandle.getCallingUserId() != userId) {
            if (UserHandle.getUserId(Binder.getCallingUid()) != userId) {
                context.enforceCallingOrSelfPermission(
                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
            }
@@ -711,35 +733,48 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
        @Override
        protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                @Nullable String[] args) {
            if (!DumpUtils.checkDumpPermission(getContext(), LOG_TAG, fout)) {
            if (!checkDumpPermission("role", fout)) {
                return;
            }

            boolean dumpAsProto = args != null && ArrayUtils.contains(args, "--proto");
            DualDumpOutputStream dumpOutputStream;
            if (dumpAsProto) {
                dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(fd));
                dumpOutputStream = new DualDumpOutputStream(new ProtoOutputStream(
                        new FileOutputStream(fd)));
            } else {
                fout.println("ROLE MANAGER STATE (dumpsys role):");
                dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, "  "));
            }

            int[] userIds = mUserManagerInternal.getUserIds();
            int userIdsLength = userIds.length;
            for (int i = 0; i < userIdsLength; i++) {
                int userId = userIds[i];
            synchronized (mLock) {
                final int userStatesSize = mUserStates.size();
                for (int i = 0; i < userStatesSize; i++) {
                    final RoleUserState userState = mUserStates.valueAt(i);

                RoleUserState userState = getOrCreateUserState(userId);
                    userState.dump(dumpOutputStream, "user_states",
                            RoleManagerServiceDumpProto.USER_STATES);
                }
            }

            dumpOutputStream.flush();
        }

        private boolean checkDumpPermission(@NonNull String serviceName,
                @NonNull PrintWriter writer) {
            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                    != PackageManager.PERMISSION_GRANTED) {
                writer.println("Permission Denial: can't dump " + serviceName + " from from pid="
                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
                        + " due to missing " + android.Manifest.permission.DUMP + " permission");
                return false;
            } else {
                return true;
            }
        }
    }

    private class Internal extends RoleManagerInternal {

        @NonNull
        @Override
        public ArrayMap<String, ArraySet<String>> getRolesAndHolders(@UserIdInt int userId) {
+6 −9
Original line number Diff line number Diff line
@@ -21,16 +21,15 @@ import android.annotation.Nullable;
import android.app.role.IRoleManager;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
import android.util.Log;

import com.android.modules.utils.BasicShellCommandHandler;

import java.io.PrintWriter;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

class RoleManagerShellCommand extends ShellCommand {

class RoleManagerShellCommand extends BasicShellCommandHandler {
    @NonNull
    private final IRoleManager mRoleManager;

@@ -39,7 +38,6 @@ class RoleManagerShellCommand extends ShellCommand {
    }

    private class CallbackFuture extends CompletableFuture<Void> {

        @NonNull
        public RemoteCallback createCallback() {
            return new RemoteCallback(result -> {
@@ -57,8 +55,7 @@ class RoleManagerShellCommand extends ShellCommand {
                get(5, TimeUnit.SECONDS);
                return 0;
            } catch (Exception e) {
                getErrPrintWriter().println("Error: see logcat for details.\n"
                        + Log.getStackTraceString(e));
                getErrPrintWriter().println("Error: see logcat for details.\n" + e);
                return -1;
            }
        }
@@ -92,7 +89,7 @@ class RoleManagerShellCommand extends ShellCommand {
        int userId = UserHandle.USER_SYSTEM;
        String option = getNextOption();
        if (option != null && option.equals("--user")) {
            userId = UserHandle.parseUserArg(getNextArgRequired());
            userId = Integer.parseInt(getNextArgRequired());
        }
        return userId;
    }
@@ -143,7 +140,7 @@ class RoleManagerShellCommand extends ShellCommand {
    public void onHelp() {
        PrintWriter pw = getOutPrintWriter();
        pw.println("Role manager (role) commands:");
        pw.println("  help");
        pw.println("  help or -h");
        pw.println("    Print this help text.");
        pw.println();
        pw.println("  add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
+8 −9
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.Xml;

import com.android.internal.annotations.GuardedBy;
@@ -55,8 +54,7 @@ import java.util.Set;
/**
 * Stores the state of roles for a user.
 */
public class RoleUserState {

class RoleUserState {
    private static final String LOG_TAG = RoleUserState.class.getSimpleName();

    public static final int VERSION_UNDEFINED = -1;
@@ -104,7 +102,7 @@ public class RoleUserState {
    private boolean mDestroyed;

    @NonNull
    private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper());
    private final Handler mWriteHandler = new Handler(BackgroundThread.get().getLooper());

    /**
     * Create a new user state, and read its state from disk if previously persisted.
@@ -392,7 +390,8 @@ public class RoleUserState {
    private void readLegacyFileLocked() {
        File file = getFile(mUserId);
        try (FileInputStream in = new AtomicFile(file).openRead()) {
            TypedXmlPullParser parser = Xml.resolvePullParser(in);
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(in, null);
            parseXmlLocked(parser);
            Slog.i(LOG_TAG, "Read roles.xml successfully");
        } catch (FileNotFoundException e) {
@@ -402,7 +401,7 @@ public class RoleUserState {
        }
    }

    private void parseXmlLocked(@NonNull TypedXmlPullParser parser) throws IOException,
    private void parseXmlLocked(@NonNull XmlPullParser parser) throws IOException,
            XmlPullParserException {
        int type;
        int depth;
@@ -421,9 +420,9 @@ public class RoleUserState {
        Slog.w(LOG_TAG, "Missing <" + TAG_ROLES + "> in roles.xml");
    }

    private void parseRolesLocked(@NonNull TypedXmlPullParser parser) throws IOException,
    private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
            XmlPullParserException {
        mVersion = parser.getAttributeInt(null, ATTRIBUTE_VERSION);
        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
        mPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
        mRoles.clear();

@@ -445,7 +444,7 @@ public class RoleUserState {
    }

    @NonNull
    private ArraySet<String> parseRoleHoldersLocked(@NonNull TypedXmlPullParser parser)
    private ArraySet<String> parseRoleHoldersLocked(@NonNull XmlPullParser parser)
            throws IOException, XmlPullParserException {
        ArraySet<String> roleHolders = new ArraySet<>();