Merge "cmd deviceidle tempwhitelist -r should clear FGS tempallowlist too" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
e487bd115f
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user