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

Commit 02232b0c authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Handle HSUM in OverlayManager shell commands

In HSUM the default user is not USER_SYSTEM, but the OverlayManager
shell commands always defaulted to this user.

This handles HSUM mode by defaulting to USER_CURRENT and resolving it to
the actual user id. This fixes the output of commands such as
"cmd overlay dump --user current state <packageName>" to no longer
include the additional defaultOverlays line, when ran in HSUM mode.

The InstallOverlayTests were also affected by HSUM mode, as the packages
were installed and uninstalled for USER_SYSTEM by default. This also
fixes the test suite by specifing the userId of the current user.

Additionally removes the mention of the userId arg in the fabricate
shell command helper, as this command is always applied for all users.

Flag: EXEMPT bugfix
Bug: 389870829
Bug: 385607637
Bug: 383212992
Test: atest InstallOverlayTests
Change-Id: Ib2ef6e3078ae6970e90b5f58507dfce7a6516a49
parent 110be912
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -44,8 +44,11 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
            "com.android.server.om.hosttest.update_overlay_test";
    private static final String DEVICE_TEST_CLS = DEVICE_TEST_PKG + ".UpdateOverlayTest";

    private int mCurrentUserid;

    @Before
    public void ensureNoOverlays() throws Exception {
        mCurrentUserid = getDevice().getCurrentUser();
        // Make sure we're starting with a clean slate.
        for (String pkg : ALL_PACKAGES) {
            assertFalse(pkg + " should not be installed", isPackageInstalled(pkg));
@@ -62,7 +65,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
    @After
    public void uninstallOverlays() throws Exception {
        for (String pkg : ALL_PACKAGES) {
            uninstallPackage(pkg);
            getDevice().uninstallPackageForUser(pkg, mCurrentUserid);
        }
    }

@@ -166,7 +169,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
        installPackage("OverlayHostTests_AppOverlayV1.apk");
        assertTrue(getDevice().executeShellCommand("cat /data/system/overlays.xml")
                .contains(APP_OVERLAY_PACKAGE_NAME));
        uninstallPackage(APP_OVERLAY_PACKAGE_NAME);
        getDevice().uninstallPackageForUser(APP_OVERLAY_PACKAGE_NAME, mCurrentUserid);
        delay();
        assertFalse(getDevice().executeShellCommand("cat /data/system/overlays.xml")
                .contains(APP_OVERLAY_PACKAGE_NAME));
@@ -200,12 +203,12 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
    }

    private void installPackage(String pkg) throws Exception {
        super.installPackage(pkg);
        super.installPackageAsUser(pkg, true /* grantPermission */, mCurrentUserid);
        delay();
    }

    private void installInstantPackage(String pkg) throws Exception {
        super.installPackage(pkg, "--instant");
        super.installPackageAsUser(pkg, true /* grantPermission */, mCurrentUserid, "--instant");
        delay();
    }

+19 −18
Original line number Diff line number Diff line
@@ -403,6 +403,20 @@ public final class OverlayManagerService extends SystemService {
        return userIds;
    }

    /**
     * Ensure that the caller has permission to interact with the given userId.
     * If the calling user is not the same as the provided user, the caller needs
     * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
     * root).
     *
     * @param userId the user to interact with
     * @param message message for any SecurityException
     */
    static int handleIncomingUser(final int userId, @NonNull final String message) {
        return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                Binder.getCallingUid(), userId, false, true, message, null);
    }

    private void handlePackageAdd(String packageName, Bundle extras, int userId) {
        final boolean replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
        if (replacing) {
@@ -1037,7 +1051,7 @@ public final class OverlayManagerService extends SystemService {
        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            final DumpState dumpState = new DumpState();
            dumpState.setUserId(UserHandle.USER_ALL);
            int userId = UserHandle.USER_ALL;

            int opti = 0;
            while (opti < args.length) {
@@ -1064,9 +1078,7 @@ public final class OverlayManagerService extends SystemService {
                        return;
                    }
                    try {
                        final int userId = UserHandle.parseUserArg(args[opti]);
                        final int realUserId = handleIncomingUser(userId, "dump");
                        dumpState.setUserId(realUserId);
                        userId = UserHandle.parseUserArg(args[opti]);
                        opti++;
                    } catch (Exception e) {
                        pw.println("Error: " + e.getMessage());
@@ -1105,6 +1117,9 @@ public final class OverlayManagerService extends SystemService {
            }

            enforceDumpPermission("dump");
            final int realUserId = userId != UserHandle.USER_ALL
                    ? handleIncomingUser(userId, "dump") : userId;
            dumpState.setUserId(realUserId);
            synchronized (mLock) {
                mImpl.dump(pw, dumpState);
                if (dumpState.getPackageName() == null) {
@@ -1113,20 +1128,6 @@ public final class OverlayManagerService extends SystemService {
            }
        }

        /**
         * Ensure that the caller has permission to interact with the given userId.
         * If the calling user is not the same as the provided user, the caller needs
         * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or
         * root).
         *
         * @param userId the user to interact with
         * @param message message for any SecurityException
         */
        private int handleIncomingUser(final int userId, @NonNull final String message) {
            return ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, false, true, message, null);
        }

        /**
         * Enforce that the caller holds the DUMP permission (or is system or root).
         *
+1 −10
Original line number Diff line number Diff line
@@ -715,20 +715,11 @@ final class OverlayManagerServiceImpl {
    }

    void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) {
        Pair<OverlayIdentifier, String> overlayIdmap = null;
        if (dumpState.getPackageName() != null) {
            OverlayIdentifier id = new OverlayIdentifier(dumpState.getPackageName(),
                    dumpState.getOverlayName());
            OverlayInfo oi = mSettings.getNullableOverlayInfo(id, USER_SYSTEM);
            if (oi != null) {
                overlayIdmap = new Pair<>(id, oi.baseCodePath);
            }
        }

        // settings
        mSettings.dump(pw, dumpState);

        // idmap data
        final var overlayIdmap = mSettings.getIdentifierAndBaseCodePath(dumpState);
        if (dumpState.getField() == null) {
            Set<Pair<OverlayIdentifier, String>> allIdmaps = (overlayIdmap != null)
                    ? Set.of(overlayIdmap) : mSettings.getAllIdentifiersAndBaseCodePaths();
+25 −1
Original line number Diff line number Diff line
@@ -212,17 +212,41 @@ final class OverlayManagerSettings {
    }

    Set<String> getAllBaseCodePaths() {
        // Overlays installed for multiple users have the same code path, avoid duplicates with Set.
        final Set<String> paths = new ArraySet<>();
        mItems.forEach(item -> paths.add(item.mBaseCodePath));
        return paths;
    }

    Set<Pair<OverlayIdentifier, String>> getAllIdentifiersAndBaseCodePaths() {
        // Overlays installed for multiple users have the same code path, avoid duplicates with Set.
        final Set<Pair<OverlayIdentifier, String>> set = new ArraySet<>();
        mItems.forEach(item -> set.add(new Pair(item.mOverlay, item.mBaseCodePath)));
        mItems.forEach(item -> set.add(new Pair<>(item.mOverlay, item.mBaseCodePath)));
        return set;
    }

    @Nullable
    Pair<OverlayIdentifier, String> getIdentifierAndBaseCodePath(@NonNull DumpState dumpState) {
        if (dumpState.getPackageName() == null) {
            return null;
        }
        OverlayIdentifier id = new OverlayIdentifier(dumpState.getPackageName(),
                dumpState.getOverlayName());
        final int userId = dumpState.getUserId();
        for (int i = 0; i < mItems.size(); i++) {
            final var item = mItems.get(i);
            if (userId != UserHandle.USER_ALL && userId != item.mUserId) {
                continue;
            }
            if (!id.equals(item.mOverlay)) {
                continue;
            }
            // Overlays installed for multiple users have the same code path, return first found.
            return new Pair<>(id, item.mBaseCodePath);
        }
        return null;
    }

    @NonNull
    List<OverlayInfo> removeIf(@NonNull final Predicate<OverlayInfo> predicate, final int userId) {
        return removeIf(info -> (predicate.test(info) && info.userId == userId));
+10 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.om;

import static com.android.internal.content.om.OverlayConfig.PARTITION_ORDER_FILE_PATH;
import static com.android.server.om.OverlayManagerService.handleIncomingUser;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -145,7 +146,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
        out.println("    Load a package and print the value of a given resource");
        out.println("    applying the current configuration and enabled overlays.");
        out.println("    For a more fine-grained alternative, use 'idmap2 lookup'.");
        out.println("  fabricate [--user USER_ID] [--target-name OVERLAYABLE] --target PACKAGE");
        out.println("  fabricate [--target-name OVERLAYABLE] --target PACKAGE");
        out.println("            --name NAME [--file FILE] ");
        out.println("            PACKAGE:TYPE/NAME ENCODED-TYPE-ID|TYPE-NAME ENCODED-VALUE");
        out.println("    Create an overlay from a single resource. Caller must be root. Example:");
@@ -160,7 +161,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
        final PrintWriter out = getOutPrintWriter();
        final PrintWriter err = getErrPrintWriter();

        int userId = UserHandle.USER_SYSTEM;
        int userId = UserHandle.USER_CURRENT;
        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
@@ -234,7 +235,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
    private int runEnableDisable(final boolean enable) throws RemoteException {
        final PrintWriter err = getErrPrintWriter();

        int userId = UserHandle.USER_SYSTEM;
        int userId = UserHandle.USER_CURRENT;
        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
@@ -269,7 +270,6 @@ final class OverlayManagerShellCommand extends ShellCommand {
            return 1;
        }

        int userId = UserHandle.USER_SYSTEM;
        String targetPackage = "";
        String targetOverlayable = "";
        String name = "";
@@ -278,9 +278,6 @@ final class OverlayManagerShellCommand extends ShellCommand {
        String config = null;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "--user":
                    userId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                case "--target":
                    targetPackage = getNextArgRequired();
                    break;
@@ -442,7 +439,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
    private int runEnableExclusive() throws RemoteException {
        final PrintWriter err = getErrPrintWriter();

        int userId = UserHandle.USER_SYSTEM;
        int userId = UserHandle.USER_CURRENT;
        boolean inCategory = false;
        String opt;
        while ((opt = getNextOption()) != null) {
@@ -469,7 +466,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
    private int runSetPriority() throws RemoteException {
        final PrintWriter err = getErrPrintWriter();

        int userId = UserHandle.USER_SYSTEM;
        int userId = UserHandle.USER_CURRENT;
        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
@@ -498,7 +495,7 @@ final class OverlayManagerShellCommand extends ShellCommand {
        final PrintWriter out = getOutPrintWriter();
        final PrintWriter err = getErrPrintWriter();

        int userId = UserHandle.USER_SYSTEM;
        int userId = UserHandle.USER_CURRENT;
        boolean verbose = false;
        String opt;
        while ((opt = getNextOption()) != null) {
@@ -525,15 +522,16 @@ final class OverlayManagerShellCommand extends ShellCommand {
            return 1;
        }

        final int realUserId = handleIncomingUser(userId, "runLookup");
        final Resources res;
        try {
            res = mContext
                .createContextAsUser(UserHandle.of(userId), /* flags */ 0)
                .createContextAsUser(UserHandle.of(realUserId), /* flags */ 0)
                .getPackageManager()
                .getResourcesForApplication(packageToLoad);
        } catch (PackageManager.NameNotFoundException e) {
            err.println(String.format("Error: failed to get resources for package %s for user %d",
                    packageToLoad, userId));
                    packageToLoad, realUserId));
            return 1;
        }
        final AssetManager assets = res.getAssets();