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

Commit 6e921d0d authored by Achim Thesmann's avatar Achim Thesmann
Browse files

Restrict PI sender BAL privileges by default.

This is a behavior change for an app that
- sends a PendingIntent created by another app
- targets Android U+
- does not explicitly set a value for `isPendingIntentBackgroundActivityLaunchAllowed`

While before U the system would automatically consider the state of the
sending app to allow the PendingIntent to start an activity from the
background, now the system automatically reduces the privilege to start only
foreground services instead.

Test: atest ActivityStarterTests BackgroundActivityLaunchTest
Bug: 244637991
Change-Id: I4860780f2ad4461ac88bf18f9774343b4ba27255
parent 9f1f2d3b
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -22,16 +22,21 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;

import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.BackgroundStartPrivileges;
import android.app.BroadcastOptions;
import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerWhitelistManager;
@@ -40,6 +45,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -56,6 +62,13 @@ import java.util.Objects;
public final class PendingIntentRecord extends IIntentSender.Stub {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM;

    /** If enabled BAL are prevented by default in applications targeting U and later. */
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
    private static final long DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER = 244637991;
    private static final String ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER =
            "enable_default_rescind_bal_privileges_from_pending_intent_sender";

    public static final int FLAG_ACTIVITY_SENDER = 1 << 0;
    public static final int FLAG_BROADCAST_SENDER = 1 << 1;
    public static final int FLAG_SERVICE_SENDER = 1 << 2;
@@ -357,17 +370,35 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
                : BackgroundStartPrivileges.NONE;
    }

    private static boolean isDefaultRescindBalPrivilegesFromPendingIntentSenderEnabled() {
        return DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                ENABLE_DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER,
                true); // assume true if the property is unknown
    }

    /**
     * Default {@link BackgroundStartPrivileges} to be used if the intent sender has not made an
     * explicit choice.
     *
     * @hide
     */
    public static BackgroundStartPrivileges getDefaultBackgroundStartPrivileges(int callingUid) {
        // TODO: In the next step this will return ALLOW_FGS instead, if the app that sent the
        // PendingIntent is targeting Android U
    @RequiresPermission(
            allOf = {
                    android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
                    android.Manifest.permission.LOG_COMPAT_CHANGE
            })
    public static BackgroundStartPrivileges getDefaultBackgroundStartPrivileges(
            int callingUid) {
        boolean isFlagEnabled = isDefaultRescindBalPrivilegesFromPendingIntentSenderEnabled();
        boolean isChangeEnabledForApp = CompatChanges.isChangeEnabled(
                DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER, callingUid);
        if (isFlagEnabled && isChangeEnabledForApp) {
            return BackgroundStartPrivileges.ALLOW_FGS;
        } else {
            return BackgroundStartPrivileges.ALLOW_BAL;
        }
    }

    @Deprecated
    public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
+6 −6
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -749,16 +750,15 @@ public class ActivityStarterTests extends WindowTestsBase {
    }

    /**
     * This test ensures that supported usecases aren't aborted when background starts are
     * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
     * this case the real calling process (pending intent) has a visible window.
     * The sending app has a visible window, but does not (by default) allow the pending intent to
     * start the background activity.
     */
    @Test
    public void
            testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowNotAborted() {
    public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() {
        doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();

        runAndVerifyBackgroundActivityStartsSubtest(
                "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
                "disallowed_realCallingUidHasVisibleWindow_abortedInU", true,
                UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
                UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP,
                false, false, false, false, false, false);