Create multiple temp allowlist types.
1. In BroadcastOptions, create multiple temp allowlist types, TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED is the default which allows both DeviceIdleController temp allowlist behavior and FGS start from background. TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED only allows DeviceIdleController temp allowlist behavior. 2. Create FgsStartTempAllowList class to contain the UIDs that is temporarily allowed to start FGS from background. Bug: 171305836 Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testTempAllowListType Change-Id: I32a14d675550cd262976bb8e16a48a070387d318
This commit is contained in:
@@ -607,7 +607,10 @@ package android.app {
|
||||
method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
|
||||
method public void setDontSendToRestrictedApps(boolean);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(int, long);
|
||||
method public android.os.Bundle toBundle();
|
||||
field public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
|
||||
field public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
|
||||
}
|
||||
|
||||
public class DownloadManager {
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Helper class for building an options Bundle that can be used with
|
||||
* {@link android.content.Context#sendBroadcast(android.content.Intent)
|
||||
@@ -30,6 +34,7 @@ import android.os.Bundle;
|
||||
@SystemApi
|
||||
public class BroadcastOptions {
|
||||
private long mTemporaryAppWhitelistDuration;
|
||||
private @TempAllowListType int mTemporaryAppWhitelistType;
|
||||
private int mMinManifestReceiverApiLevel = 0;
|
||||
private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
|
||||
private boolean mDontSendToRestrictedApps = false;
|
||||
@@ -42,6 +47,9 @@ public class BroadcastOptions {
|
||||
static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
|
||||
= "android:broadcast.temporaryAppWhitelistDuration";
|
||||
|
||||
static final String KEY_TEMPORARY_APP_WHITELIST_TYPE
|
||||
= "android:broadcast.temporaryAppWhitelistType";
|
||||
|
||||
/**
|
||||
* Corresponds to {@link #setMinManifestReceiverApiLevel}.
|
||||
*/
|
||||
@@ -66,6 +74,27 @@ public class BroadcastOptions {
|
||||
static final String KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS =
|
||||
"android:broadcast.allowBackgroundActivityStarts";
|
||||
|
||||
/**
|
||||
* Allow the temp allowlist behavior, plus allow foreground service start from background.
|
||||
*/
|
||||
public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0;
|
||||
/**
|
||||
* Only allow the temp allowlist behavior, not allow foreground service start from
|
||||
* background.
|
||||
*/
|
||||
public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1;
|
||||
|
||||
/**
|
||||
* The list of temp allowlist types.
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(flag = true, prefix = { "TEMPORARY_WHITELIST_TYPE_" }, value = {
|
||||
TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
|
||||
TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface TempAllowListType {}
|
||||
|
||||
public static BroadcastOptions makeBasic() {
|
||||
BroadcastOptions opts = new BroadcastOptions();
|
||||
return opts;
|
||||
@@ -77,6 +106,7 @@ public class BroadcastOptions {
|
||||
/** @hide */
|
||||
public BroadcastOptions(Bundle opts) {
|
||||
mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION);
|
||||
mTemporaryAppWhitelistType = opts.getInt(KEY_TEMPORARY_APP_WHITELIST_TYPE);
|
||||
mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0);
|
||||
mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL,
|
||||
Build.VERSION_CODES.CUR_DEVELOPMENT);
|
||||
@@ -95,6 +125,22 @@ public class BroadcastOptions {
|
||||
android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
|
||||
public void setTemporaryAppWhitelistDuration(long duration) {
|
||||
mTemporaryAppWhitelistDuration = duration;
|
||||
mTemporaryAppWhitelistType = TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a duration for which the system should temporary place an application on the
|
||||
* power allowlist when this broadcast is being delivered to it, specify the temp allowlist
|
||||
* type.
|
||||
* @param type one of {@link TempAllowListType}
|
||||
* @param duration the duration in milliseconds; 0 means to not place on allowlist.
|
||||
*/
|
||||
@RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
|
||||
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
|
||||
android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
|
||||
public void setTemporaryAppWhitelistDuration(@TempAllowListType int type, long duration) {
|
||||
mTemporaryAppWhitelistDuration = duration;
|
||||
mTemporaryAppWhitelistType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,6 +151,14 @@ public class BroadcastOptions {
|
||||
return mTemporaryAppWhitelistDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link #mTemporaryAppWhitelistType}.
|
||||
* @hide
|
||||
*/
|
||||
public @TempAllowListType int getTemporaryAppWhitelistType() {
|
||||
return mTemporaryAppWhitelistType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum target API level of receivers of the broadcast. If an application
|
||||
* is targeting an API level less than this, the broadcast will not be delivered to
|
||||
@@ -190,6 +244,9 @@ public class BroadcastOptions {
|
||||
if (mTemporaryAppWhitelistDuration > 0) {
|
||||
b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration);
|
||||
}
|
||||
if (mTemporaryAppWhitelistType != 0) {
|
||||
b.putInt(KEY_TEMPORARY_APP_WHITELIST_TYPE, mTemporaryAppWhitelistType);
|
||||
}
|
||||
if (mMinManifestReceiverApiLevel != 0) {
|
||||
b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.app.ActivityThread;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.ApplicationExitInfo;
|
||||
import android.app.BroadcastOptions;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IServiceConnection;
|
||||
import android.app.Notification;
|
||||
@@ -3201,7 +3202,8 @@ public final class ActiveServices {
|
||||
+ " for fg-service launch");
|
||||
}
|
||||
mAm.tempWhitelistUidLocked(r.appInfo.uid,
|
||||
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
|
||||
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch",
|
||||
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
|
||||
}
|
||||
|
||||
if (!mPendingServices.contains(r)) {
|
||||
@@ -5284,8 +5286,9 @@ public final class ActiveServices {
|
||||
|
||||
if (ret == FGS_FEATURE_DENIED) {
|
||||
if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
|
||||
&& mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
|
||||
// uid is on DeviceIdleController's allowlist.
|
||||
&& mAm.isWhitelistedForFgsStartLocked(r.appInfo.uid)) {
|
||||
// uid is on DeviceIdleController's user/system allowlist
|
||||
// or AMS's FgsStartTempAllowList.
|
||||
ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,6 +1096,11 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|
||||
final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this);
|
||||
|
||||
/**
|
||||
* The temp-allowlist that is allowed to start FGS from background.
|
||||
*/
|
||||
final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList();
|
||||
|
||||
/**
|
||||
* Information about and control over application operations
|
||||
*/
|
||||
@@ -5513,6 +5518,12 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
|| mPendingTempWhitelist.indexOfKey(uid) >= 0;
|
||||
}
|
||||
|
||||
boolean isWhitelistedForFgsStartLocked(int uid) {
|
||||
final int appId = UserHandle.getAppId(uid);
|
||||
return Arrays.binarySearch(mDeviceIdleExceptIdleWhitelist, appId) >= 0
|
||||
|| mFgsStartTempAllowList.isAllowed(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
|
||||
* the whitelist
|
||||
@@ -15327,17 +15338,22 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
tempWhitelistUidLocked(targetUid, duration, tag);
|
||||
tempWhitelistUidLocked(targetUid, duration, tag,
|
||||
BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whitelists {@code targetUid} to temporarily bypass Power Save mode.
|
||||
*/
|
||||
@GuardedBy("this")
|
||||
void tempWhitelistUidLocked(int targetUid, long duration, String tag) {
|
||||
void tempWhitelistUidLocked(int targetUid, long duration, String tag, int type) {
|
||||
mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
|
||||
setUidTempWhitelistStateLocked(targetUid, true);
|
||||
mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget();
|
||||
|
||||
if (type == BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
|
||||
mFgsStartTempAllowList.add(targetUid, duration);
|
||||
}
|
||||
}
|
||||
|
||||
void pushTempWhitelist() {
|
||||
|
||||
@@ -896,7 +896,8 @@ public final class BroadcastQueue {
|
||||
return false;
|
||||
}
|
||||
|
||||
final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r) {
|
||||
final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r,
|
||||
@BroadcastOptions.TempAllowListType int type) {
|
||||
if (duration > Integer.MAX_VALUE) {
|
||||
duration = Integer.MAX_VALUE;
|
||||
}
|
||||
@@ -919,9 +920,9 @@ public final class BroadcastQueue {
|
||||
}
|
||||
if (DEBUG_BROADCAST) {
|
||||
Slog.v(TAG, "Broadcast temp whitelist uid=" + uid + " duration=" + duration
|
||||
+ " : " + b.toString());
|
||||
+ " type=" + type + " : " + b.toString());
|
||||
}
|
||||
mService.tempWhitelistUidLocked(uid, duration, b.toString());
|
||||
mService.tempWhitelistUidLocked(uid, duration, b.toString(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1318,7 +1319,8 @@ public final class BroadcastQueue {
|
||||
}
|
||||
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
|
||||
scheduleTempWhitelistLocked(filter.owningUid,
|
||||
brOptions.getTemporaryAppWhitelistDuration(), r);
|
||||
brOptions.getTemporaryAppWhitelistDuration(), r,
|
||||
brOptions.getTemporaryAppWhitelistType());
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -1610,7 +1612,8 @@ public final class BroadcastQueue {
|
||||
(brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0);
|
||||
if (isActivityCapable) {
|
||||
scheduleTempWhitelistLocked(receiverUid,
|
||||
brOptions.getTemporaryAppWhitelistDuration(), r);
|
||||
brOptions.getTemporaryAppWhitelistDuration(), r,
|
||||
brOptions.getTemporaryAppWhitelistType());
|
||||
}
|
||||
|
||||
// Broadcast is being executed, its package can't be stopped.
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.am;
|
||||
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
/**
|
||||
* List of uids that are temporarily allowed to start FGS from background.
|
||||
*/
|
||||
final class FgsStartTempAllowList {
|
||||
private static final int MAX_SIZE = 100;
|
||||
/**
|
||||
* The key is the UID, the value is expiration elapse time in ms of this temp-allowed UID.
|
||||
*/
|
||||
private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
|
||||
|
||||
FgsStartTempAllowList() {
|
||||
}
|
||||
|
||||
void add(int uid, long duration) {
|
||||
if (duration <= 0) {
|
||||
Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: " + uid);
|
||||
return;
|
||||
}
|
||||
// The temp allowlist should be a short list with only a few entries in it.
|
||||
final int size = mTempAllowListFgs.size();
|
||||
if (size > MAX_SIZE) {
|
||||
Slog.w(TAG_AM, "FgsStartTempAllowList length:" + size + " exceeds " + MAX_SIZE);
|
||||
}
|
||||
final long now = SystemClock.elapsedRealtime();
|
||||
for (int index = mTempAllowListFgs.size() - 1; index >= 0; index--) {
|
||||
if (mTempAllowListFgs.valueAt(index) < now) {
|
||||
mTempAllowListFgs.removeAt(index);
|
||||
}
|
||||
}
|
||||
final long existingExpirationTime = mTempAllowListFgs.get(uid, -1);
|
||||
final long expirationTime = now + duration;
|
||||
if (existingExpirationTime == -1 || existingExpirationTime < expirationTime) {
|
||||
mTempAllowListFgs.put(uid, expirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isAllowed(int uid) {
|
||||
final int index = mTempAllowListFgs.indexOfKey(uid);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
} else if (mTempAllowListFgs.valueAt(index) < SystemClock.elapsedRealtime()) {
|
||||
mTempAllowListFgs.removeAt(index);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user