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

Commit f4312ccb authored by Mårten Kongstad's avatar Mårten Kongstad Committed by Ryan Mitchell
Browse files

OMS: replace OMSImpl.OverlayChangeListener with return values

Remove the listener callback triggered when the OMS settings have
changed. Teach the OMSImpl methods to return the equivalent information
instead: an Optional<T> of the target package and Android user who's
overlays need to be refreshed, or an exception in case of error.

This is the first step towards an OMS transactional API, where multiple
requests can be batched together and the outcome is either that all
operations succeed, or some operation fails and (to the outside system)
nothing happens. Replacing callbacks with explicit return values allow
the caller more control of what data is exposed to the rest of Android.

Bug: 119916381
Test: atest FrameworksServicesTests:com.android.server.om OverlayDeviceTests OverlayHostTests CtsAppSecurityHostTestCases:OverlayHostTest
Change-Id: If58d5e9ddeec649e708224bb29efcc38ebe51bf7
parent ecae4298
Loading
Loading
Loading
Loading
+119 −49
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import static android.os.Trace.TRACE_TAG_RRO;
import static android.os.Trace.traceBegin;
import static android.os.Trace.traceEnd;

import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -88,6 +90,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

/**
 * Service to manage asset overlays.
@@ -238,6 +241,10 @@ public final class OverlayManagerService extends SystemService {

    private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);

    private final Consumer<PackageAndUser> mOnOverlaysChanged = (pair) -> {
        onOverlaysChanged(pair.packageName, pair.userId);
    };

    public OverlayManagerService(@NonNull final Context context) {
        super(context);
        try {
@@ -249,8 +256,7 @@ public final class OverlayManagerService extends SystemService {
            IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager);
            mSettings = new OverlayManagerSettings();
            mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
                    OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
                    new OverlayChangeListener());
                    OverlayConfig.getSystemInstance(), getDefaultOverlayPackages());
            mActorEnforcer = new OverlayActorEnforcer(mPackageManager);

            final IntentFilter packageFilter = new IntentFilter();
@@ -396,10 +402,17 @@ public final class OverlayManagerService extends SystemService {
                                false);
                        if (pi != null && !pi.applicationInfo.isInstantApp()) {
                            mPackageManager.cachePackageInfo(packageName, userId, pi);

                            try {
                                if (pi.isOverlayPackage()) {
                                mImpl.onOverlayPackageAdded(packageName, userId);
                                    mImpl.onOverlayPackageAdded(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                } else {
                                mImpl.onTargetPackageAdded(packageName, userId);
                                    mImpl.onTargetPackageAdded(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                }
                            } catch (OperationFailedException e) {
                                Slog.e(TAG, "onPackageAdded internal error", e);
                            }
                        }
                    }
@@ -419,10 +432,17 @@ public final class OverlayManagerService extends SystemService {
                                false);
                        if (pi != null && pi.applicationInfo.isInstantApp()) {
                            mPackageManager.cachePackageInfo(packageName, userId, pi);

                            try {
                                if (pi.isOverlayPackage()) {
                                mImpl.onOverlayPackageChanged(packageName, userId);
                                    mImpl.onOverlayPackageChanged(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                }  else {
                                mImpl.onTargetPackageChanged(packageName, userId);
                                    mImpl.onTargetPackageChanged(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                }
                            } catch (OperationFailedException e) {
                                Slog.e(TAG, "onPackageChanged internal error", e);
                            }
                        }
                    }
@@ -441,7 +461,12 @@ public final class OverlayManagerService extends SystemService {
                        mPackageManager.forgetPackageInfo(packageName, userId);
                        final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
                        if (oi != null) {
                            mImpl.onOverlayPackageReplacing(packageName, userId);
                            try {
                                mImpl.onOverlayPackageReplacing(packageName, userId)
                                    .ifPresent(mOnOverlaysChanged);
                            } catch (OperationFailedException e) {
                                Slog.e(TAG, "onPackageReplacing internal error", e);
                            }
                        }
                    }
                }
@@ -460,10 +485,16 @@ public final class OverlayManagerService extends SystemService {
                                false);
                        if (pi != null && !pi.applicationInfo.isInstantApp()) {
                            mPackageManager.cachePackageInfo(packageName, userId, pi);
                            try {
                                if (pi.isOverlayPackage()) {
                                mImpl.onOverlayPackageReplaced(packageName, userId);
                                    mImpl.onOverlayPackageReplaced(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                } else {
                                mImpl.onTargetPackageReplaced(packageName, userId);
                                    mImpl.onTargetPackageReplaced(packageName, userId)
                                        .ifPresent(mOnOverlaysChanged);
                                }
                            } catch (OperationFailedException e) {
                                Slog.e(TAG, "onPackageReplaced internal error", e);
                            }
                        }
                    }
@@ -481,10 +512,17 @@ public final class OverlayManagerService extends SystemService {
                    synchronized (mLock) {
                        mPackageManager.forgetPackageInfo(packageName, userId);
                        final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);

                        try {
                            if (oi != null) {
                            mImpl.onOverlayPackageRemoved(packageName, userId);
                                mImpl.onOverlayPackageRemoved(packageName, userId)
                                    .ifPresent(mOnOverlaysChanged);
                            } else {
                            mImpl.onTargetPackageRemoved(packageName, userId);
                                mImpl.onTargetPackageRemoved(packageName, userId)
                                    .ifPresent(mOnOverlaysChanged);
                            }
                        } catch (OperationFailedException e) {
                            Slog.e(TAG, "onPackageRemoved internal error", e);
                        }
                    }
                }
@@ -602,7 +640,13 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setEnabled(packageName, enable, realUserId);
                        try {
                            mImpl.setEnabled(packageName, enable, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -627,8 +671,14 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
                                realUserId);
                        try {
                            mImpl.setEnabledExclusive(packageName,
                                    false /* withinCategory */, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -654,8 +704,14 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
                                realUserId);
                        try {
                            mImpl.setEnabledExclusive(packageName,
                                    true /* withinCategory */, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -681,7 +737,13 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setPriority(packageName, parentPackageName, realUserId);
                        try {
                            mImpl.setPriority(packageName, parentPackageName, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -705,7 +767,13 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setHighestPriority(packageName, realUserId);
                        try {
                            mImpl.setHighestPriority(packageName, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -729,7 +797,13 @@ public final class OverlayManagerService extends SystemService {
                final long ident = Binder.clearCallingIdentity();
                try {
                    synchronized (mLock) {
                        return mImpl.setLowestPriority(packageName, realUserId);
                        try {
                            mImpl.setLowestPriority(packageName, realUserId)
                                .ifPresent(mOnOverlaysChanged);
                            return true;
                        } catch (OperationFailedException e) {
                            return false;
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(ident);
@@ -898,10 +972,7 @@ public final class OverlayManagerService extends SystemService {
        }
    };

    private final class OverlayChangeListener
            implements OverlayManagerServiceImpl.OverlayChangeListener {
        @Override
        public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
    private void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
        schedulePersistSettings();
        FgThread.getHandler().post(() -> {
            updateAssets(userId, targetPackageName);
@@ -915,15 +986,14 @@ public final class OverlayManagerService extends SystemService {
            }

            try {
                    ActivityManager.getService().broadcastIntentWithFeature(null, null, intent,
                            null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE,
                            null, false, false, userId);
                ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
                        null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
                        userId);
            } catch (RemoteException e) {
                // Intentionally left empty.
            }
        });
    }
    }

    /**
     * Updates the target packages' set of enabled overlays in PackageManager.
+98 −74

File changed.

Preview size limit exceeded, changes collapsed.

+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.om;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;

final class PackageAndUser {
    public final @NonNull String packageName;
    public final @UserIdInt int userId;

    PackageAndUser(@NonNull String packageName, @UserIdInt int userId) {
        this.packageName = packageName;
        this.userId = userId;
    }

    @Override
    public boolean equals(@Nullable Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof PackageAndUser)) {
            return false;
        }
        PackageAndUser other = (PackageAndUser) obj;
        return packageName.equals(other.packageName) && userId == other.userId;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + packageName.hashCode();
        result = prime * result + userId;
        return result;
    }

    @Override
    public String toString() {
        return String.format("PackageAndUser{packageName=%s, userId=%d}", packageName, userId);
    }
}
+5 −5
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
    }

    @Test
    public void testImmutableEnabledChange() {
    public void testImmutableEnabledChange() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -106,7 +106,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
    }

    @Test
    public void testMutableEnabledChangeHasNoEffect() {
    public void testMutableEnabledChangeHasNoEffect() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -134,7 +134,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
    }

    @Test
    public void testMutableEnabledToImmutableEnabled() {
    public void testMutableEnabledToImmutableEnabled() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -178,7 +178,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
    }

    @Test
    public void testMutablePriorityChange() {
    public void testMutablePriorityChange() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -218,7 +218,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
    }

    @Test
    public void testImmutablePriorityChange() {
    public void testImmutablePriorityChange() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
+37 −39
Original line number Diff line number Diff line
@@ -22,11 +22,14 @@ import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
import static android.os.OverlayablePolicy.CONFIG_SIGNATURE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.testng.Assert.assertThrows;

import android.content.om.OverlayInfo;
import android.util.Pair;

import androidx.test.runner.AndroidJUnit4;

@@ -35,6 +38,7 @@ import org.junit.runner.RunWith;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@RunWith(AndroidJUnit4.class)
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
@@ -55,7 +59,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    private static final String CERT_CONFIG_NOK = "config_certificate_nok";

    @Test
    public void testGetOverlayInfo() {
    public void testGetOverlayInfo() throws Exception {
        installNewPackage(overlay(OVERLAY, TARGET), USER);

        final OverlayManagerServiceImpl impl = getImpl();
@@ -67,7 +71,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testGetOverlayInfosForTarget() {
    public void testGetOverlayInfosForTarget() throws Exception {
        installNewPackage(overlay(OVERLAY, TARGET), USER);
        installNewPackage(overlay(OVERLAY2, TARGET), USER);
        installNewPackage(overlay(OVERLAY3, TARGET), USER2);
@@ -92,7 +96,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testGetOverlayInfosForUser() {
    public void testGetOverlayInfosForUser() throws Exception {
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET), USER);
        installNewPackage(overlay(OVERLAY2, TARGET), USER);
@@ -119,7 +123,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testPriority() {
    public void testPriority() throws Exception {
        installNewPackage(overlay(OVERLAY, TARGET), USER);
        installNewPackage(overlay(OVERLAY2, TARGET), USER);
        installNewPackage(overlay(OVERLAY3, TARGET), USER);
@@ -131,18 +135,21 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes

        assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);

        assertTrue(impl.setLowestPriority(OVERLAY3, USER));
        assertEquals(impl.setLowestPriority(OVERLAY3, USER),
                Optional.of(new PackageAndUser(TARGET, USER)));
        assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2);

        assertTrue(impl.setHighestPriority(OVERLAY3, USER));
        assertEquals(impl.setHighestPriority(OVERLAY3, USER),
                Optional.of(new PackageAndUser(TARGET, USER)));
        assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3);

        assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER));
        assertEquals(impl.setPriority(OVERLAY, OVERLAY2, USER),
                Optional.of(new PackageAndUser(TARGET, USER)));
        assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3);
    }

    @Test
    public void testOverlayInfoStateTransitions() {
    public void testOverlayInfoStateTransitions() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        assertNull(impl.getOverlayInfo(OVERLAY, USER));

@@ -153,7 +160,8 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
        installNewPackage(target, USER);
        assertState(STATE_DISABLED, OVERLAY, USER);

        impl.setEnabled(OVERLAY, true, USER);
        assertEquals(impl.setEnabled(OVERLAY, true, USER),
                Optional.of(new PackageAndUser(TARGET, USER)));
        assertState(STATE_ENABLED, OVERLAY, USER);

        // target upgrades do not change the state of the overlay
@@ -168,50 +176,40 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testOnOverlayPackageUpgraded() {
        final FakeListener listener = getListener();
    public void testOnOverlayPackageUpgraded() throws Exception {
        final FakeDeviceState.PackageBuilder target = target(TARGET);
        final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET);
        installNewPackage(target, USER);
        installNewPackage(overlay, USER);
        listener.count = 0;
        upgradePackage(overlay, USER);
        assertEquals(2, listener.count);

        // upgrade to a version where the overlay has changed its target
        // expect once for the old target package, once for the new target package
        listener.count = 0;
        final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target");
        final Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> pair =
                upgradePackage(overlay2, USER);
        assertEquals(3, listener.count);

        listener.count = 0;
        upgradePackage(overlay2, USER);
        assertEquals(2, listener.count);
        assertEquals(pair.first, Optional.of(new PackageAndUser(TARGET, USER)));
        assertEquals(pair.second, Optional.of(new PackageAndUser("some.other.target", USER)));
    }

    @Test
    public void testListener() {
    public void testSetEnabledAtVariousConditions() throws Exception {
        final OverlayManagerServiceImpl impl = getImpl();
        final FakeListener listener = getListener();
        installNewPackage(overlay(OVERLAY, TARGET), USER);
        assertEquals(1, listener.count);
        listener.count = 0;
        assertThrows(OverlayManagerServiceImpl.OperationFailedException.class,
                () -> impl.setEnabled(OVERLAY, true, USER));

        // request succeeded, and there was a change that needs to be
        // propagated to the rest of the system
        installNewPackage(target(TARGET), USER);
        assertEquals(1, listener.count);
        listener.count = 0;

        impl.setEnabled(OVERLAY, true, USER);
        assertEquals(1, listener.count);
        listener.count = 0;
        installNewPackage(overlay(OVERLAY, TARGET), USER);
        assertEquals(impl.setEnabled(OVERLAY, true, USER),
                Optional.of(new PackageAndUser(TARGET, USER)));

        impl.setEnabled(OVERLAY, true, USER);
        assertEquals(0, listener.count);
        // request succeeded, but nothing changed
        assertFalse(impl.setEnabled(OVERLAY, true, USER).isPresent());
    }

    @Test
    public void testConfigSignaturePolicyOk() {
    public void testConfigSignaturePolicyOk() throws Exception {
        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
        reinitializeImpl();

@@ -229,7 +227,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testConfigSignaturePolicyCertNok() {
    public void testConfigSignaturePolicyCertNok() throws Exception {
        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
        reinitializeImpl();

@@ -247,7 +245,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testConfigSignaturePolicyNoConfig() {
    public void testConfigSignaturePolicyNoConfig() throws Exception {
        addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER);
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);
@@ -262,7 +260,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testConfigSignaturePolicyNoRefPkg() {
    public void testConfigSignaturePolicyNoRefPkg() throws Exception {
        installNewPackage(target(TARGET), USER);
        installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER);

@@ -276,7 +274,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
    }

    @Test
    public void testConfigSignaturePolicyRefPkgNotSystem() {
    public void testConfigSignaturePolicyRefPkgNotSystem() throws Exception {
        setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
        reinitializeImpl();

Loading