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

Commit 861f263f authored by Winson's avatar Winson
Browse files

Allow any actor when target package is debuggable

Also adds comprehensive tests for ActorState in overlayable
actor enforcement. These tests work by mirroring the logic
branches in the actual method, but using test data instead.

This technically doesn't run every combination of parameters,
but that would be a massive set. This branching approach should
be sufficient. It has fully replaced the previous set of
manually written test cases.

Bug: 150390069

Test: atest com.android.server.om.OverlayActorEnforcerTests
Test: atest OverlayRemountedTest

Change-Id: Iabf8b93307ee51ecced41335fdf47eb59c15c365
parent f52bdb9c
Loading
Loading
Loading
Loading
+30 −15
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;

@@ -66,7 +67,7 @@ public class OverlayActorEnforcer {

        String actorNamespace = actorUri.getAuthority();
        Map<String, String> namespace = namedActors.get(actorNamespace);
        if (namespace == null) {
        if (ArrayUtils.isEmpty(namespace)) {
            return Pair.create(null, ActorState.MISSING_NAMESPACE);
        }

@@ -102,21 +103,32 @@ public class OverlayActorEnforcer {
     * See {@link OverlayActorEnforcer} class comment for actor requirements.
     * @return true if the actor is allowed to act on the target overlayInfo
     */
    private ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
            int callingUid, int userId) {
        // Checked first to avoid package not found errors, which are ignored for calls from shell
        switch (callingUid) {
            case Process.ROOT_UID:
            case Process.SYSTEM_UID:
                return ActorState.ALLOWED;
        }

        final String targetPackageName = overlayInfo.targetPackageName;
        final PackageInfo targetPkgInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
        if (targetPkgInfo == null) {
            return ActorState.TARGET_NOT_FOUND;
        }

        if ((targetPkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            return ActorState.ALLOWED;
        }

        String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
        if (ArrayUtils.isEmpty(callingPackageNames)) {
            return ActorState.NO_PACKAGES_FOR_UID;
        }

        // A target is always an allowed actor for itself
        String targetPackageName = overlayInfo.targetPackageName;
        if (ArrayUtils.contains(callingPackageNames, targetPackageName)) {
            return ActorState.ALLOWED;
        }
@@ -149,7 +161,7 @@ public class OverlayActorEnforcer {
            targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
                    targetOverlayableName, userId);
        } catch (IOException e) {
            return ActorState.UNABLE_TO_GET_TARGET;
            return ActorState.UNABLE_TO_GET_TARGET_OVERLAYABLE;
        }

        if (targetOverlayable == null) {
@@ -189,7 +201,7 @@ public class OverlayActorEnforcer {
        }

        // Currently only pre-installed apps can be actors
        if (!appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
        if (!appInfo.isSystemApp()) {
            return ActorState.ACTOR_NOT_PREINSTALLED;
        }

@@ -203,22 +215,25 @@ public class OverlayActorEnforcer {
    /**
     * For easier logging/debugging, a set of all possible failure/success states when running
     * enforcement.
     *
     * The ordering of this enum should be maintained in the order that cases are checked in code,
     * as this ordering is used inside OverlayActorEnforcerTests.
     */
    public enum ActorState {
        ALLOWED,
        INVALID_ACTOR,
        MISSING_NAMESPACE,
        MISSING_PACKAGE,
        MISSING_APP_INFO,
        ACTOR_NOT_PREINSTALLED,
        TARGET_NOT_FOUND,
        NO_PACKAGES_FOR_UID,
        MISSING_ACTOR_NAME,
        ERROR_READING_OVERLAYABLE,
        MISSING_TARGET_OVERLAYABLE_NAME,
        MISSING_LEGACY_PERMISSION,
        ERROR_READING_OVERLAYABLE,
        UNABLE_TO_GET_TARGET_OVERLAYABLE,
        MISSING_OVERLAYABLE,
        INVALID_OVERLAYABLE_ACTOR_NAME,
        NO_NAMED_ACTORS,
        UNABLE_TO_GET_TARGET,
        MISSING_LEGACY_PERMISSION
        MISSING_NAMESPACE,
        MISSING_ACTOR_NAME,
        MISSING_APP_INFO,
        ACTOR_NOT_PREINSTALLED,
        INVALID_ACTOR,
        ALLOWED
    }
}
+336 −121

File changed.

Preview size limit exceeded, changes collapsed.

+3 −2
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ fun <Type : Any?> whenever(mock: Type, block: InvocationOnMock.() -> Any?) =

fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }

inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit): T {
inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit = {}): T {
    val swappingAnswer = object : Answer<Any?> {
        var delegate: Answer<*> = Answers.RETURNS_DEFAULTS

@@ -81,4 +81,5 @@ inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit): T {
            }
}

inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit) = spyThrowOnUnmocked<T>(null, block)
inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit = {}) =
        spyThrowOnUnmocked<T>(null, block)