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

Commit e487bd11 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "`cmd deviceidle tempwhitelist -r` should clear FGS tempallowlist too" into sc-dev

parents bf8849c1 321f0bd4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -547,7 +547,7 @@ public class DeviceIdleController extends SystemService
    private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];

    /**
     * List of end times for UIDs that are temporarily marked as being allowed to access
     * List of end times for app-IDs that are temporarily marked as being allowed to access
     * the network and acquire wakelocks. Times are in milliseconds.
     */
    private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
+15 −11
Original line number Diff line number Diff line
@@ -1236,7 +1236,7 @@ public class ActivityManagerService extends IActivityManager.Stub
     * The temp-allowlist that is allowed to start FGS from background.
     */
    @CompositeRWLock({"this", "mProcLock"})
    final FgsTempAllowList<Integer, FgsTempAllowListItem> mFgsStartTempAllowList =
    final FgsTempAllowList<FgsTempAllowListItem> mFgsStartTempAllowList =
            new FgsTempAllowList();
    static final FgsTempAllowListItem FAKE_TEMP_ALLOW_LIST_ITEM = new FgsTempAllowListItem(
@@ -1246,7 +1246,7 @@ public class ActivityManagerService extends IActivityManager.Stub
     * List of uids that are allowed to have while-in-use permission when FGS is started from
     * background.
     */
    private final FgsTempAllowList<Integer, String> mFgsWhileInUseTempAllowList =
    private final FgsTempAllowList<String> mFgsWhileInUseTempAllowList =
            new FgsTempAllowList();
    /**
@@ -9372,22 +9372,17 @@ public class ActivityManagerService extends IActivityManager.Stub
            pw.println("  mFgsStartTempAllowList:");
            final long currentTimeNow = System.currentTimeMillis();
            final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
            final Set<Integer> uids = new ArraySet<>(mFgsStartTempAllowList.keySet());
            for (Integer uid : uids) {
                final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
                if (entry == null) {
                    continue;
                }
            mFgsStartTempAllowList.forEach((uid, entry) -> {
                pw.print("    " + UserHandle.formatUid(uid) + ": ");
                entry.second.dump(pw); pw.println();
                pw.print("ms expiration=");
                entry.second.dump(pw);
                pw.print(" 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) {
@@ -15345,10 +15340,19 @@ public class ActivityManagerService extends IActivityManager.Stub
                    mDeviceIdleTempAllowlist = appids;
                    if (adding) {
                        if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
                            // Note, the device idle temp-allowlist are by app-ids, but here
                            // mFgsStartTempAllowList contains UIDs.
                            mFgsStartTempAllowList.add(changingUid, durationMs,
                                    new FgsTempAllowListItem(durationMs, reasonCode, reason,
                                    callingUid));
                        }
                    } else {
                        // Note in the removing case, we need to remove all the UIDs matching
                        // the appId, because DeviceIdle's temp-allowlist are based on AppIds,
                        // not UIDs.
                        // For eacmple, "cmd deviceidle tempallowlist -r PACKAGE" will
                        // not only remove this app for user 0, but for all users.
                        mFgsStartTempAllowList.removeAppId(UserHandle.getAppId(changingUid));
                    }
                    setAppIdTempAllowlistStateLSP(changingUid, adding);
                }
+46 −23
Original line number Diff line number Diff line
@@ -20,11 +20,12 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;

import android.annotation.Nullable;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;

import java.util.Set;
import java.util.function.BiConsumer;

/**
 * List of keys that have expiration time.
@@ -33,19 +34,18 @@ import java.util.Set;
 *
 * <p>This is used for both FGS-BG-start restriction, and FGS-while-in-use permissions check.</p>
 *
 * <p>Note: the underlying data structure is an {@link ArrayMap}, for performance reason, it is only
 * suitable to hold up to hundreds of entries.</p>
 * @param <K> type of the key.
 * <p>Note: the underlying data structure is an {@link SparseArray}, for performance reason,
 * it is only suitable to hold up to hundreds of entries.</p>
 * @param <E> type of the additional optional info.
 */
public class FgsTempAllowList<K, E> {
public class FgsTempAllowList<E> {
    private static final int DEFAULT_MAX_SIZE = 100;

    /**
     * The value is Pair type, Pair.first is the expirationTime(an elapsedRealtime),
     * Pair.second is the optional information entry about this key.
     */
    private final ArrayMap<K, Pair<Long, E>> mTempAllowList = new ArrayMap<>();
    private final SparseArray<Pair<Long, E>> mTempAllowList = new SparseArray<>();
    private int mMaxSize = DEFAULT_MAX_SIZE;
    private final Object mLock = new Object();

@@ -70,15 +70,14 @@ public class FgsTempAllowList<K, E> {

    /**
     * Add a key and its duration with optional info into the temp allowlist.
     * @param key
     * @param durationMs temp-allowlisted duration in milliseconds.
     * @param entry additional optional information of this key, could be null.
     */
    public void add(K key, long durationMs, @Nullable E entry) {
    public void add(int uid, long durationMs, @Nullable E entry) {
        synchronized (mLock) {
            if (durationMs <= 0) {
                Slog.e(TAG_AM, "FgsTempAllowList bad duration:" + durationMs + " key: "
                        + key);
                        + uid);
                return;
            }
            // The temp allowlist should be a short list with only a few entries in it.
@@ -94,10 +93,10 @@ public class FgsTempAllowList<K, E> {
                    }
                }
            }
            final Pair<Long, E> existing = mTempAllowList.get(key);
            final Pair<Long, E> existing = mTempAllowList.get(uid);
            final long expirationTime = now + durationMs;
            if (existing == null || existing.first < expirationTime) {
                mTempAllowList.put(key, new Pair(expirationTime, entry));
                mTempAllowList.put(uid, new Pair(expirationTime, entry));
            }
        }
    }
@@ -105,13 +104,12 @@ public class FgsTempAllowList<K, E> {
    /**
     * If the key has not expired (AKA allowed), return its non-null value.
     * If the key has expired, return null.
     * @param key
     * @return
     */
    @Nullable
    public Pair<Long, E> get(K key) {
    public Pair<Long, E> get(int uid) {
        synchronized (mLock) {
            final int index = mTempAllowList.indexOfKey(key);
            final int index = mTempAllowList.indexOfKey(uid);
            if (index < 0) {
                return null;
            } else if (mTempAllowList.valueAt(index).first < SystemClock.elapsedRealtime()) {
@@ -126,23 +124,48 @@ public class FgsTempAllowList<K, E> {
    /**
     * If the key has not expired (AKA allowed), return true.
     * If the key has expired, return false.
     * @param key
     * @return
     */
    public boolean isAllowed(K key) {
        Pair<Long, E> entry = get(key);
    public boolean isAllowed(int uid) {
        Pair<Long, E> entry = get(uid);
        return entry != null;
    }

    public void remove(K key) {
    /**
     * Remove a given UID.
     */
    public void removeUid(int uid) {
        synchronized (mLock) {
            mTempAllowList.remove(key);
            mTempAllowList.remove(uid);
        }
    }

    public Set<K> keySet() {
    /**
     * Remove by appId.
     */
    public void removeAppId(int appId) {
        synchronized (mLock) {
            return mTempAllowList.keySet();
            // Find all UIDs matching the appId.
            for (int i = mTempAllowList.size() - 1; i >= 0; i--) {
                final int uid = mTempAllowList.keyAt(i);
                if (UserHandle.getAppId(uid) == appId) {
                    mTempAllowList.removeAt(i);
                }
            }
        }
    }

    /**
     * Iterate over the entries.
     */
    public void forEach(BiConsumer<Integer, Pair<Long, E>> callback) {
        synchronized (mLock) {
            for (int i = 0; i < mTempAllowList.size(); i++) {
                final int uid = mTempAllowList.keyAt(i);
                final Pair<Long, E> entry = mTempAllowList.valueAt(i);
                if (entry != null) {
                    callback.accept(uid, entry);
                }
            }
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -3074,7 +3074,7 @@ public final class ProcessList {
                                UidRecord.CHANGE_GONE);
                        EventLogTags.writeAmUidStopped(uid);
                        mActiveUids.remove(uid);
                        mService.mFgsStartTempAllowList.remove(record.info.uid);
                        mService.mFgsStartTempAllowList.removeUid(record.info.uid);
                        mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
                                ActivityManager.PROCESS_CAPABILITY_NONE);
                    }
+53 −3
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@ import android.util.Pair;

import org.junit.Test;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * Build/Install/Run:
 *  atest FrameworksServicesTests:TempAllowListTest
@@ -41,7 +44,7 @@ public class FgsTempAllowListTest {
     */
    @Test
    public void testIsAllowed() {
        FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
        FgsTempAllowList<String> allowList = new FgsTempAllowList();
        allowList.add(10001, 2000, "description1");
        allowList.add(10002, 2000, "description2");

@@ -55,7 +58,7 @@ public class FgsTempAllowListTest {
        assertNotNull(entry2);
        assertEquals(entry2.second, "description2");

        allowList.remove(10001);
        allowList.removeUid(10001);
        assertFalse(allowList.isAllowed(10001));
        assertNull(allowList.get(10001));
    }
@@ -65,7 +68,7 @@ public class FgsTempAllowListTest {
     */
    @Test
    public void testExpired() {
        FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
        FgsTempAllowList<String> allowList = new FgsTempAllowList();
        // temp allow for 2000ms.
        allowList.add(10001, 2000, "uid1-2000ms");
        // sleep for 3000ms.
@@ -74,4 +77,51 @@ public class FgsTempAllowListTest {
        assertFalse(allowList.isAllowed(10001));
        assertNull(allowList.get(10001));
    }

    @Test
    public void testRemoveAppId() {
        FgsTempAllowList<String> allowList = new FgsTempAllowList();
        allowList.add(10001, 2000, "description1");
        allowList.add(10002, 2000, "description2");
        allowList.add(10_10001, 2000, "description3");

        assertTrue(allowList.isAllowed(10001));
        assertTrue(allowList.isAllowed(10002));
        assertTrue(allowList.isAllowed(10_10001));

        allowList.removeAppId(10001);

        assertFalse(allowList.isAllowed(10001));
        assertTrue(allowList.isAllowed(10002));
        assertFalse(allowList.isAllowed(10_10001));
    }

    @Test
    public void testForEach() {
        final FgsTempAllowList<String> allowList = new FgsTempAllowList();


        // Call forEach(), return the sum of all the UIDs, and make sure the item is
        // "uid" + uid.
        final Supplier<Integer> callForEach = () -> {
            final AtomicInteger sum = new AtomicInteger();
            sum.set(0);
            allowList.forEach((uid, entry) -> {
                sum.set(sum.get() + uid);
                assertEquals(entry.second, "uid" + uid);
            });
            return sum.get();
        };

        // Call on th empty list.
        assertEquals(0, (int) callForEach.get());

        // Add one item.
        allowList.add(1, 2000, "uid1");
        assertEquals(1, (int) callForEach.get());

        // Add one more item.
        allowList.add(10, 2000, "uid10");
        assertEquals(11, (int) callForEach.get());
    }
}