Merge "Allow exemption of roles/permissions from broadcast response events." into tm-dev am: d79cb12422
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18639261 Change-Id: I2699cc1b39ad11144c87fafc509ad478a1a2b1fe Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -280,6 +280,20 @@ public interface AppStandbyInternal {
|
||||
*/
|
||||
boolean shouldNoteResponseEventForAllBroadcastSessions();
|
||||
|
||||
/**
|
||||
* Returns the list of roles whose holders are exempted from the requirement of starting
|
||||
* a response event after receiving a broadcast.
|
||||
*/
|
||||
@NonNull
|
||||
List<String> getBroadcastResponseExemptedRoles();
|
||||
|
||||
/**
|
||||
* Returns the list of permissions whose holders are exempted from the requirement of starting
|
||||
* a response event after receiving a broadcast.
|
||||
*/
|
||||
@NonNull
|
||||
List<String> getBroadcastResponseExemptedPermissions();
|
||||
|
||||
/**
|
||||
* Return the last known value corresponding to the {@code key} from
|
||||
* {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController.
|
||||
|
||||
@@ -100,6 +100,7 @@ import android.os.UserHandle;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings.Global;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.IndentingPrintWriter;
|
||||
@@ -420,6 +421,26 @@ public class AppStandbyController
|
||||
volatile boolean mNoteResponseEventForAllBroadcastSessions =
|
||||
ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS;
|
||||
|
||||
/**
|
||||
* List of roles whose holders are exempted from the requirement of starting
|
||||
* a response event after receiving a broadcast.
|
||||
*
|
||||
* The list of roles will be separated by '|' in the string.
|
||||
*/
|
||||
volatile String mBroadcastResponseExemptedRoles =
|
||||
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES;
|
||||
volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST;
|
||||
|
||||
/**
|
||||
* List of permissions whose holders are exempted from the requirement of starting
|
||||
* a response event after receiving a broadcast.
|
||||
*
|
||||
* The list of permissions will be separated by '|' in the string.
|
||||
*/
|
||||
volatile String mBroadcastResponseExemptedPermissions =
|
||||
ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS;
|
||||
volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST;
|
||||
|
||||
/**
|
||||
* Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}.
|
||||
*
|
||||
@@ -1959,6 +1980,18 @@ public class AppStandbyController
|
||||
return mNoteResponseEventForAllBroadcastSessions;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<String> getBroadcastResponseExemptedRoles() {
|
||||
return mBroadcastResponseExemptedRolesList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<String> getBroadcastResponseExemptedPermissions() {
|
||||
return mBroadcastResponseExemptedPermissionsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getAppStandbyConstant(@NonNull String key) {
|
||||
@@ -2311,6 +2344,14 @@ public class AppStandbyController
|
||||
pw.print(mNoteResponseEventForAllBroadcastSessions);
|
||||
pw.println();
|
||||
|
||||
pw.print(" mBroadcastResponseExemptedRoles");
|
||||
pw.print(mBroadcastResponseExemptedRoles);
|
||||
pw.println();
|
||||
|
||||
pw.print(" mBroadcastResponseExemptedPermissions");
|
||||
pw.print(mBroadcastResponseExemptedPermissions);
|
||||
pw.println();
|
||||
|
||||
pw.println();
|
||||
pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
|
||||
pw.print(" mAllowRestrictedBucket=");
|
||||
@@ -2795,6 +2836,10 @@ public class AppStandbyController
|
||||
"broadcast_sessions_with_response_duration_ms";
|
||||
private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
||||
"note_response_event_for_all_broadcast_sessions";
|
||||
private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES =
|
||||
"brodacast_response_exempted_roles";
|
||||
private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS =
|
||||
"brodacast_response_exempted_permissions";
|
||||
|
||||
public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS =
|
||||
COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR;
|
||||
@@ -2837,6 +2882,11 @@ public class AppStandbyController
|
||||
2 * ONE_MINUTE;
|
||||
public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
|
||||
true;
|
||||
private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = "";
|
||||
private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = "";
|
||||
|
||||
private final TextUtils.SimpleStringSplitter mStringPipeSplitter =
|
||||
new TextUtils.SimpleStringSplitter('|');
|
||||
|
||||
ConstantsObserver(Handler handler) {
|
||||
super(handler);
|
||||
@@ -2989,6 +3039,20 @@ public class AppStandbyController
|
||||
KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
|
||||
DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS);
|
||||
break;
|
||||
case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES:
|
||||
mBroadcastResponseExemptedRoles = properties.getString(
|
||||
KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES,
|
||||
DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES);
|
||||
mBroadcastResponseExemptedRolesList = splitPipeSeparatedString(
|
||||
mBroadcastResponseExemptedRoles);
|
||||
break;
|
||||
case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS:
|
||||
mBroadcastResponseExemptedPermissions = properties.getString(
|
||||
KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS,
|
||||
DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS);
|
||||
mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString(
|
||||
mBroadcastResponseExemptedPermissions);
|
||||
break;
|
||||
default:
|
||||
if (!timeThresholdsUpdated
|
||||
&& (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD)
|
||||
@@ -3003,6 +3067,15 @@ public class AppStandbyController
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitPipeSeparatedString(String string) {
|
||||
final List<String> values = new ArrayList<>();
|
||||
mStringPipeSplitter.setString(string);
|
||||
while (mStringPipeSplitter.hasNext()) {
|
||||
values.add(mStringPipeSplitter.next());
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private void updateTimeThresholds() {
|
||||
// Query the values as an atomic set.
|
||||
final DeviceConfig.Properties screenThresholdProperties =
|
||||
|
||||
@@ -23,15 +23,23 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager.ProcessState;
|
||||
import android.app.role.OnRoleHoldersChangedListener;
|
||||
import android.app.role.RoleManager;
|
||||
import android.app.usage.BroadcastResponseStats;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.permission.PermissionManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.LongArrayQueue;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -71,14 +79,33 @@ class BroadcastResponseStatsTracker {
|
||||
private SparseArray<SparseArray<UserBroadcastResponseStats>> mUserResponseStats =
|
||||
new SparseArray<>();
|
||||
|
||||
/**
|
||||
* Cache of package names holding exempted roles.
|
||||
*
|
||||
* Contains the mapping of userId -> {roleName -> <packages>} data.
|
||||
*/
|
||||
// TODO: Use SparseArrayMap to simplify the logic.
|
||||
@GuardedBy("mLock")
|
||||
private SparseArray<ArrayMap<String, List<String>>> mExemptedRoleHoldersCache =
|
||||
new SparseArray<>();
|
||||
private final OnRoleHoldersChangedListener mRoleHoldersChangedListener =
|
||||
this::onRoleHoldersChanged;
|
||||
|
||||
private AppStandbyInternal mAppStandby;
|
||||
private BroadcastResponseStatsLogger mLogger;
|
||||
private RoleManager mRoleManager;
|
||||
|
||||
BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) {
|
||||
mAppStandby = appStandby;
|
||||
mLogger = new BroadcastResponseStatsLogger();
|
||||
}
|
||||
|
||||
void onSystemServicesReady(Context context) {
|
||||
mRoleManager = context.getSystemService(RoleManager.class);
|
||||
mRoleManager.addOnRoleHoldersChangedListenerAsUser(BackgroundThread.getExecutor(),
|
||||
mRoleHoldersChangedListener, UserHandle.ALL);
|
||||
}
|
||||
|
||||
// TODO (206518114): Move all callbacks handling to a handler thread.
|
||||
void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage,
|
||||
UserHandle targetUser, long idForResponseEvent,
|
||||
@@ -86,10 +113,19 @@ class BroadcastResponseStatsTracker {
|
||||
mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser,
|
||||
idForResponseEvent, timestampMs, targetUidProcState);
|
||||
if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) {
|
||||
// No need to track the broadcast response state while the target app is
|
||||
// No need to track the broadcast response stats while the target app is
|
||||
// in the foreground.
|
||||
return;
|
||||
}
|
||||
if (doesPackageHoldExemptedRole(targetPackage, targetUser)) {
|
||||
// Package holds an exempted role, so no need to track the broadcast response stats.
|
||||
return;
|
||||
}
|
||||
if (doesPackageHoldExemptedPermission(targetPackage, targetUser)) {
|
||||
// Package holds an exempted permission, so no need to track the broadcast response
|
||||
// stats
|
||||
return;
|
||||
}
|
||||
synchronized (mLock) {
|
||||
final ArraySet<BroadcastEvent> broadcastEvents =
|
||||
getOrCreateBroadcastEventsLocked(targetPackage, targetUser);
|
||||
@@ -253,6 +289,62 @@ class BroadcastResponseStatsTracker {
|
||||
}
|
||||
}
|
||||
|
||||
boolean doesPackageHoldExemptedRole(@NonNull String packageName, @NonNull UserHandle user) {
|
||||
final List<String> exemptedRoles = mAppStandby.getBroadcastResponseExemptedRoles();
|
||||
synchronized (mLock) {
|
||||
for (int i = exemptedRoles.size() - 1; i >= 0; --i) {
|
||||
final String roleName = exemptedRoles.get(i);
|
||||
final List<String> roleHolders = getRoleHoldersLocked(roleName, user);
|
||||
if (CollectionUtils.contains(roleHolders, packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean doesPackageHoldExemptedPermission(@NonNull String packageName,
|
||||
@NonNull UserHandle user) {
|
||||
final List<String> exemptedPermissions = mAppStandby
|
||||
.getBroadcastResponseExemptedPermissions();
|
||||
for (int i = exemptedPermissions.size() - 1; i >= 0; --i) {
|
||||
final String permissionName = exemptedPermissions.get(i);
|
||||
if (PermissionManager.checkPackageNamePermission(permissionName, packageName,
|
||||
user.getIdentifier()) == PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private List<String> getRoleHoldersLocked(@NonNull String roleName, @NonNull UserHandle user) {
|
||||
ArrayMap<String, List<String>> roleHoldersForUser = mExemptedRoleHoldersCache.get(
|
||||
user.getIdentifier());
|
||||
if (roleHoldersForUser == null) {
|
||||
roleHoldersForUser = new ArrayMap<>();
|
||||
mExemptedRoleHoldersCache.put(user.getIdentifier(), roleHoldersForUser);
|
||||
}
|
||||
List<String> roleHolders = roleHoldersForUser.get(roleName);
|
||||
if (roleHolders == null && mRoleManager != null) {
|
||||
roleHolders = mRoleManager.getRoleHoldersAsUser(roleName, user);
|
||||
roleHoldersForUser.put(roleName, roleHolders);
|
||||
}
|
||||
return roleHolders;
|
||||
}
|
||||
|
||||
private void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
|
||||
synchronized (mLock) {
|
||||
final ArrayMap<String, List<String>> roleHoldersForUser =
|
||||
mExemptedRoleHoldersCache.get(user.getIdentifier());
|
||||
if (roleHoldersForUser == null) {
|
||||
return;
|
||||
}
|
||||
roleHoldersForUser.remove(roleName);
|
||||
}
|
||||
}
|
||||
|
||||
void onUserRemoved(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
mUserBroadcastEvents.remove(userId);
|
||||
@@ -260,6 +352,7 @@ class BroadcastResponseStatsTracker {
|
||||
for (int i = mUserResponseStats.size() - 1; i >= 0; --i) {
|
||||
mUserResponseStats.valueAt(i).remove(userId);
|
||||
}
|
||||
mExemptedRoleHoldersCache.remove(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +466,8 @@ class BroadcastResponseStatsTracker {
|
||||
ipw.println();
|
||||
dumpResponseStatsLocked(ipw);
|
||||
ipw.println();
|
||||
dumpRoleHoldersLocked(ipw);
|
||||
ipw.println();
|
||||
mLogger.dumpLogs(ipw);
|
||||
}
|
||||
|
||||
@@ -417,5 +512,32 @@ class BroadcastResponseStatsTracker {
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void dumpRoleHoldersLocked(@NonNull IndentingPrintWriter ipw) {
|
||||
ipw.println("Role holders:");
|
||||
ipw.increaseIndent();
|
||||
for (int userIdx = 0; userIdx < mExemptedRoleHoldersCache.size(); ++userIdx) {
|
||||
final int userId = mExemptedRoleHoldersCache.keyAt(userIdx);
|
||||
final ArrayMap<String, List<String>> roleHoldersForUser =
|
||||
mExemptedRoleHoldersCache.valueAt(userIdx);
|
||||
ipw.println("User " + userId + ":");
|
||||
ipw.increaseIndent();
|
||||
for (int roleIdx = 0; roleIdx < roleHoldersForUser.size(); ++roleIdx) {
|
||||
final String roleName = roleHoldersForUser.keyAt(roleIdx);
|
||||
final List<String> holders = roleHoldersForUser.valueAt(roleIdx);
|
||||
ipw.print(roleName + ": ");
|
||||
for (int holderIdx = 0; holderIdx < holders.size(); ++holderIdx) {
|
||||
if (holderIdx > 0) {
|
||||
ipw.print(", ");
|
||||
}
|
||||
ipw.print(holders.get(holderIdx));
|
||||
}
|
||||
ipw.println();
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -357,6 +357,7 @@ public class UsageStatsService extends SystemService implements
|
||||
getDpmInternal();
|
||||
// initialize mShortcutServiceInternal
|
||||
getShortcutServiceInternal();
|
||||
mResponseStatsTracker.onSystemServicesReady(getContext());
|
||||
|
||||
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user