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

Commit deaee3b9 authored by felkachang's avatar felkachang
Browse files

OverlayManagerImpl support to commit OverlayManagerTransaction

The major task of OverlayManagerImpl is to create not only a frro
file but also an idmap file for a FabricatedOverlay instance. The
app attaches multiple FabricatedOverlay instances into an
OverlayManagerTransaction.

This patch makes OverlayManagerImpl process multiple requests in the
OverlayManagerTransaction in one commitment.

Test: atest \
          OverlayHostTests \
          OverlayDeviceTests \
          SelfTargetingOverlayDeviceTests \
          OverlayRemountedTest \
          FrameworksServicesTests:com.android.server.om \
          CtsContentTestCases:android.content.om.cts \
          idmap2_tests

Bug: 205919743
Change-Id: I22e45fb6b3935cea4b24038dbd82d84bc9ca7db3
parent a8fc0153
Loading
Loading
Loading
Loading
+51 −3
Original line number Diff line number Diff line
@@ -17,14 +17,20 @@
package com.android.internal.content.om;

import static android.content.Context.MODE_PRIVATE;
import static android.content.om.OverlayManagerTransaction.Request.BUNDLE_FABRICATED_OVERLAY;
import static android.content.om.OverlayManagerTransaction.Request.TYPE_REGISTER_FABRICATED;
import static android.content.om.OverlayManagerTransaction.Request.TYPE_UNREGISTER_FABRICATED;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.internal.content.om.OverlayConfig.DEFAULT_PRIORITY;

import android.annotation.NonNull;
import android.annotation.NonUiContext;
import android.content.Context;
import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManagerTransaction;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.parsing.FrameworkParsingPackageUtils;
@@ -48,6 +54,7 @@ import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@@ -129,10 +136,9 @@ public class OverlayManagerImpl {
        }
    }

    /**
     * Ensure the base dir for self-targeting is valid.
     */
    /** Ensure the base dir for self-targeting is valid. */
    @VisibleForTesting
    @NonUiContext
    public void ensureBaseDir() {
        final String baseApkPath = mContext.getApplicationInfo().getBaseCodePath();
        final Path baseApkFolderName = Path.of(baseApkPath).getParent().getFileName();
@@ -217,6 +223,7 @@ public class OverlayManagerImpl {
     *
     * @param overlayInternal the FabricatedOverlayInternal to be saved.
     */
    @NonUiContext
    public void registerFabricatedOverlay(@NonNull FabricatedOverlayInternal overlayInternal)
            throws IOException, PackageManager.NameNotFoundException {
        ensureBaseDir();
@@ -263,6 +270,7 @@ public class OverlayManagerImpl {
     *
     * @param overlayName the specific name
     */
    @NonUiContext
    public void unregisterFabricatedOverlay(@NonNull String overlayName) {
        ensureBaseDir();
        checkOverlayNameValid(overlayName);
@@ -277,6 +285,46 @@ public class OverlayManagerImpl {
        }
    }

    /**
     * Commit the overlay manager transaction
     *
     * @param transaction the overlay manager transaction
     */
    @NonUiContext
    public void commit(@NonNull OverlayManagerTransaction transaction)
            throws PackageManager.NameNotFoundException, IOException {
        Objects.requireNonNull(transaction);

        for (Iterator<OverlayManagerTransaction.Request> it = transaction.iterator();
                it.hasNext(); ) {
            final OverlayManagerTransaction.Request request = it.next();
            if (request.type == TYPE_REGISTER_FABRICATED) {
                final FabricatedOverlayInternal fabricatedOverlayInternal =
                        Objects.requireNonNull(
                                request.extras.getParcelable(
                                        BUNDLE_FABRICATED_OVERLAY,
                                        FabricatedOverlayInternal.class));

                // populate the mandatory data
                if (TextUtils.isEmpty(fabricatedOverlayInternal.packageName)) {
                    fabricatedOverlayInternal.packageName = mContext.getPackageName();
                } else {
                    if (!TextUtils.equals(
                            fabricatedOverlayInternal.packageName, mContext.getPackageName())) {
                        throw new IllegalArgumentException("Unknown package name in transaction");
                    }
                }

                registerFabricatedOverlay(fabricatedOverlayInternal);
            } else if (request.type == TYPE_UNREGISTER_FABRICATED) {
                final OverlayIdentifier overlayIdentifier = Objects.requireNonNull(request.overlay);
                unregisterFabricatedOverlay(overlayIdentifier.getOverlayName());
            } else {
                throw new IllegalArgumentException("Unknown request in transaction " + request);
            }
        }
    }

    /**
     * Get the list of overlays information for the target package name.
     *
+36 −0
Original line number Diff line number Diff line
@@ -31,7 +31,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManagerTransaction;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
@@ -450,6 +452,40 @@ public class OverlayManagerImplTest {
        assertThrows(IllegalArgumentException.class, overlayManagerImpl::ensureBaseDir);
    }

    @Test
    public void commit_withNullTransaction_shouldFail() {
        assertThrows(NullPointerException.class, () -> mOverlayManagerImpl.commit(null));
    }

    @Test
    public void commitRegisterOverlay_fromOtherBuilder_shouldWork()
            throws PackageManager.NameNotFoundException, IOException {
        FabricatedOverlay overlay =
                new FabricatedOverlay.Builder(
                                mContext.getPackageName(), mOverlayName, mContext.getPackageName())
                        .setTargetOverlayable(SIGNATURE_OVERLAYABLE)
                        .setResourceValue(
                                TARGET_COLOR_RES, TypedValue.TYPE_INT_COLOR_ARGB8, Color.WHITE)
                        .build();
        OverlayManagerTransaction transaction =
                new OverlayManagerTransaction.Builder().registerFabricatedOverlay(overlay).build();

        mOverlayManagerImpl.commit(transaction);

        final List<OverlayInfo> overlayInfos =
                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
        final int firstNumberOfOverlays = overlayInfos.size();
        expect.that(firstNumberOfOverlays).isEqualTo(1);
        final OverlayInfo overlayInfo = overlayInfos.get(0);
        expect.that(overlayInfo).isNotNull();
        Truth.assertThat(expect.hasFailures()).isFalse();
        expect.that(overlayInfo.isFabricated()).isTrue();
        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
    }

    @Test
    public void newOverlayManagerImpl_forOtherUser_shouldFail() {
        Context fakeContext =