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

Commit 002676b2 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Automerger Merge Worker
Browse files

Merge "Allow exemption of roles/permissions from broadcast response events."...

Merge "Allow exemption of roles/permissions from broadcast response events." into tm-dev am: d79cb124

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18639261



Change-Id: Ia0b2c85f88aece48a5c08d12e0f9b3226b2d3477
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 9d4bb2f4 d79cb124
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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.
+73 −0
Original line number Diff line number Diff line
@@ -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 =
+123 −1
Original line number Diff line number Diff line
@@ -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();
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -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 {