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

Commit 36429f87 authored by Hui Yu's avatar Hui Yu
Browse files

Allow FGS started from MediaButtonReceiver to have while-in-use

permissions.

1. Create a generic FgsTempAllowList class, mFgsStartTempAllowList and
 mFgsWhileInUseTempAllowList are instantiated from FgsTempAllowList.
2. For mFgsWhileInUseTempAllowList, the uid on this list is allowed to
have while-in-use permission when the FGS is started from background for
a duration of time.
3. When media button is pressed, the targetUid is added to
mFgsWhileInUseTempAllowList, for the duration of 10 seconds, this way the
targetUid can start FGS from background and have while-in-use permission.
4. When checking for ProcessRecord.
mAllowBackgroundActivityStartsTokens, it is the caller app's
ProcessRecord should be checked instead of the service's ProcessRecord.

Bug: 182481312
Test: use b/167998084 reproduce steps, make a voip call, the
 receiver side screen is unlocked, the receiver side uses bluetooth
headset button to pick up the call, "dumpsys activity -a" shows the FGS
has "allowWhileInUsePermissionInFgs=true" and "isForeground=true".

Change-Id: Ic80aefe4202fe2210881bb8eea24b6e34cb1e7d0
parent ef9e6a7c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -185,6 +185,11 @@ public class PowerExemptionManager {
    public static final int REASON_OP_ACTIVATE_VPN = 68;
    /** @hide */
    public static final int REASON_OP_ACTIVATE_PLATFORM_VPN = 69;
    /**
     * Temporarily allowed to have FGS while-in-use permissions.
     * @hide
     */
    public static final int REASON_TEMP_ALLOWED_WHILE_IN_USE = 70;

    /* BG-FGS-launch is allowed by temp-allow-list or system-allow-list.
       Reason code for temp and system allow list starts here.
@@ -347,6 +352,7 @@ public class PowerExemptionManager {
            REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD,
            REASON_OP_ACTIVATE_VPN,
            REASON_OP_ACTIVATE_PLATFORM_VPN,
            REASON_TEMP_ALLOWED_WHILE_IN_USE,
            // temp and system allow list reasons.
            REASON_GEOFENCING,
            REASON_PUSH_MESSAGING,
@@ -608,6 +614,8 @@ public class PowerExemptionManager {
                return "OP_ACTIVATE_VPN";
            case REASON_OP_ACTIVATE_PLATFORM_VPN:
                return "OP_ACTIVATE_PLATFORM_VPN";
            case REASON_TEMP_ALLOWED_WHILE_IN_USE:
                return "TEMP_ALLOWED_WHILE_IN_USE";
            case REASON_GEOFENCING:
                return "GEOFENCING";
            case REASON_PUSH_MESSAGING:
+5 −0
Original line number Diff line number Diff line
@@ -570,4 +570,9 @@ public abstract class ActivityManagerInternal {

    /** Unregister an {@link AnrController} */
    public abstract void unregisterAnrController(AnrController controller);

    /**
     * Is the FGS started from an uid temporarily allowed to have while-in-use permission?
     */
    public abstract boolean isTempAllowlistedForFgsWhileInUse(int uid);
}
+20 −5
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
@@ -5643,6 +5644,12 @@ public final class ActiveServices {
            }
        }

        if (ret == REASON_DENIED) {
            if (mAm.mInternal.isTempAllowlistedForFgsWhileInUse(callingUid)) {
                return REASON_TEMP_ALLOWED_WHILE_IN_USE;
            }
        }

        if (ret == REASON_DENIED) {
            if (targetService != null && targetService.app != null) {
                ActiveInstrumentation instr = targetService.app.getActiveInstrumentation();
@@ -5691,7 +5698,7 @@ public final class ActiveServices {
    private @ReasonCode int shouldAllowFgsStartForegroundLocked(
            @ReasonCode int allowWhileInUse, String callingPackage, int callingPid,
            int callingUid, Intent intent, ServiceRecord r, int userId) {
        FgsStartTempAllowList.TempFgsAllowListEntry tempAllowListReason =
        ActivityManagerService.FgsTempAllowListItem tempAllowListReason =
                r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
        int ret = shouldAllowFgsStartForegroundLocked(allowWhileInUse, callingPid, callingUid,
                callingPackage, r);
@@ -5790,13 +5797,13 @@ public final class ActiveServices {
        }

        if (ret == REASON_DENIED) {
            FgsStartTempAllowList.TempFgsAllowListEntry entry =
            ActivityManagerService.FgsTempAllowListItem item =
                    mAm.isAllowlistedForFgsStartLOSP(callingUid);
            if (entry != null) {
                if (entry == ActivityManagerService.FAKE_TEMP_ALLOWLIST_ENTRY) {
            if (item != null) {
                if (item == ActivityManagerService.FAKE_TEMP_ALLOW_LIST_ITEM) {
                    ret = REASON_SYSTEM_ALLOW_LISTED;
                } else {
                    ret = entry.mReasonCode;
                    ret = item.mReasonCode;
                }
            }
        }
@@ -5921,4 +5928,12 @@ public final class ActiveServices {
                durationMs,
                r.mStartForegroundCount);
    }

    boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
            String callingPackage) {
        return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
                /* targetService */ null,
                /* allowBackgroundActivityStarts */ false)
                != REASON_DENIED;
    }
}
+22 −0
Original line number Diff line number Diff line
@@ -36,4 +36,26 @@ public interface ActivityManagerLocal {
     * @return whether the app will be able to start a foreground service or not.
     */
    boolean canStartForegroundService(int pid, int uid, @NonNull String packageName);

    /**
     * Returns {@code true} if a foreground service started by an uid is allowed to have
     * while-in-use permissions.
     *
     * @param pid The process id belonging to the app to be checked.
     * @param uid The UID of the app to be checked.
     * @param packageName The package name of the app to be checked.
     * @return whether the foreground service is allowed to have while-in-use permissions.
     * @hide
     */
    boolean canAllowWhileInUsePermissionInFgs(int pid, int uid, @NonNull String packageName);

    /**
     * Temporarily allow foreground service started by an uid to have while-in-use permission
     * for durationMs.
     *
     * @param uid The UID of the app that starts the foreground service.
     * @param durationMs elapsedRealTime duration in milliseconds.
     * @hide
     */
    void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs);
}
+81 −12
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.Process.BLUETOOTH_UID;
import static android.os.Process.FIRST_APPLICATION_UID;
@@ -258,6 +258,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerExemptionManager;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.PowerExemptionManager.TempAllowListType;
import android.os.PowerManager;
@@ -1201,15 +1202,45 @@ public class ActivityManagerService extends IActivityManager.Stub
    @CompositeRWLock({"this", "mProcLock"})
    final PendingTempAllowlists mPendingTempAllowlist = new PendingTempAllowlists(this);
    public static final class FgsTempAllowListItem {
        final long mDuration;
        final @PowerExemptionManager.ReasonCode int mReasonCode;
        final String mReason;
        final int mCallingUid;
        FgsTempAllowListItem(long duration, @PowerExemptionManager.ReasonCode int reasonCode,
                String reason, int callingUid) {
            mDuration = duration;
            mReasonCode = reasonCode;
            mReason = reason;
            mCallingUid = callingUid;
        }
        void dump(PrintWriter pw) {
            pw.print(" duration=" + mDuration +
                    " callingUid=" + UserHandle.formatUid(mCallingUid) +
                    " reasonCode=" + PowerExemptionManager.reasonCodeToString(mReasonCode) +
                    " reason=" + mReason);
        }
    }
    /**
     * The temp-allowlist that is allowed to start FGS from background.
     */
    @CompositeRWLock({"this", "mProcLock"})
    final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList();
    final FgsTempAllowList<Integer, FgsTempAllowListItem> mFgsStartTempAllowList =
            new FgsTempAllowList();
    static final FgsTempAllowListItem FAKE_TEMP_ALLOW_LIST_ITEM = new FgsTempAllowListItem(
            Long.MAX_VALUE, REASON_SYSTEM_ALLOW_LISTED, "", INVALID_UID);
    /*
     * List of uids that are allowed to have while-in-use permission when FGS is started from
     * background.
     */
    private final FgsTempAllowList<Integer, String> mFgsWhileInUseTempAllowList =
            new FgsTempAllowList();
    static final FgsStartTempAllowList.TempFgsAllowListEntry FAKE_TEMP_ALLOWLIST_ENTRY = new
            FgsStartTempAllowList.TempFgsAllowListEntry(Long.MAX_VALUE, Long.MAX_VALUE,
            REASON_SYSTEM_ALLOW_LISTED, "", INVALID_UID);
    /**
     * Information about and control over application operations
     */
@@ -5563,11 +5594,12 @@ public class ActivityManagerService extends IActivityManager.Stub
     */
    @Nullable
    @GuardedBy(anyOf = {"this", "mProcLock"})
    FgsStartTempAllowList.TempFgsAllowListEntry isAllowlistedForFgsStartLOSP(int uid) {
    FgsTempAllowListItem isAllowlistedForFgsStartLOSP(int uid) {
        if (Arrays.binarySearch(mDeviceIdleExceptIdleAllowlist, UserHandle.getAppId(uid)) >= 0) {
            return FAKE_TEMP_ALLOWLIST_ENTRY;
            return FAKE_TEMP_ALLOW_LIST_ITEM;
        }
        return mFgsStartTempAllowList.getAllowedDurationAndReason(uid);
        final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
        return entry == null ? null : entry.second;
    }
    /**
@@ -9263,7 +9295,24 @@ public class ActivityManagerService extends IActivityManager.Stub
                }
            }
            pw.println("  mFgsStartTempAllowList:");
            mFgsStartTempAllowList.dump(pw);
            final long currentTimeNow = System.currentTimeMillis();
            final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
            final Set<Integer> uids = mFgsStartTempAllowList.keySet();
            for (Integer uid : uids) {
                final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
                if (entry == null) {
                    continue;
                }
                pw.print("    " + UserHandle.formatUid(uid) + ": ");
                entry.second.dump(pw); pw.println();
                pw.print("ms expiration=");
                // Convert entry.mExpirationTime, which is an elapsed time since boot,
                // to a time since epoch (i.e. System.currentTimeMillis()-based time.)
                final long expirationInCurrentTime =
                        currentTimeNow - elapsedRealtimeNow + entry.first;
                TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
                pw.println();
            }
        }
        if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                || mOrigWaitForDebugger) {
@@ -14539,7 +14588,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            mUiHandler.obtainMessage(PUSH_TEMP_ALLOWLIST_UI_MSG).sendToTarget();
            if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
                mFgsStartTempAllowList.add(targetUid, duration, reasonCode, reason, callingUid);
                mFgsStartTempAllowList.add(targetUid, duration,
                        new FgsTempAllowListItem(duration, reasonCode, reason, callingUid));
            }
        }
    }
@@ -15212,8 +15262,9 @@ public class ActivityManagerService extends IActivityManager.Stub
                    mDeviceIdleTempAllowlist = appids;
                    if (adding) {
                        if (type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
                            mFgsStartTempAllowList.add(changingUid, durationMs, reasonCode, reason,
                                    callingUid);
                            mFgsStartTempAllowList.add(changingUid, durationMs,
                                    new FgsTempAllowListItem(durationMs, reasonCode, reason,
                                    callingUid));
                        }
                    }
                    setAppIdTempAllowlistStateLSP(changingUid, adding);
@@ -16032,6 +16083,24 @@ public class ActivityManagerService extends IActivityManager.Stub
                return mServices.canStartForegroundServiceLocked(pid, uid, packageName);
            }
        }
        @Override
        public void tempAllowWhileInUsePermissionInFgs(int uid, long durationMs) {
            mFgsWhileInUseTempAllowList.add(uid, durationMs, "");
        }
        @Override
        public boolean isTempAllowlistedForFgsWhileInUse(int uid) {
            return mFgsWhileInUseTempAllowList.isAllowed(uid);
        }
        @Override
        public boolean canAllowWhileInUsePermissionInFgs(int pid, int uid,
                @NonNull String packageName) {
            synchronized (ActivityManagerService.this) {
                return mServices.canAllowWhileInUsePermissionInFgsLocked(pid, uid, packageName);
            }
        }
    }
    long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
Loading