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

Commit a5d44e88 authored by Hai Zhang's avatar Hai Zhang
Browse files

Refactor RoleManagerService to use system API when possible.

Changes include but not limited to:

- Use DataOutputStream for computePackageStateHash(), as
OutputStream.write(int) only writes one byte, so it's better to use a
proper built-in mechanism and drop dependency on another util class in
the meantime.

- Use a simplified enforceCrossUserPermission() similar to other
system services, instead of the non-API
ActivityManager.handleIncomingUser().

- Use the module library BasicShellCommandHandler to implement
RoleManagerShellCommand.

- Dump the existing user states, instead of for all users which
potentially creates empty states. This makes the dump more truthful
and saves an API.

- Use a local copy of checkDumpPermission() instead of depending on
the entire DumpUtils class.

- Use the XmlPullParser API instead of the new non-API
TypedXmlPullParser, because the legacy file can only be written before
R, and thus can't be the new binary XML format.

- Other small changes to use system APIs.

Bug: 158736025
Test: CtsRoleTestCases
Change-Id: I97d74aadfa2ccd264929c45226367b65a47f6435
parent 80401a0a
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<>();