Loading apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +22 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,28 @@ public interface AppStandbyInternal { @ProcessState int getBroadcastResponseFgThresholdState(); /** * Returns the duration within which any broadcasts occurred will be treated as one broadcast * session. */ long getBroadcastSessionsDurationMs(); /** * Returns the duration within which any broadcasts occurred (with a corresponding response * event) will be treated as one broadcast session. This similar to * {@link #getBroadcastSessionsDurationMs()}, except that this duration will be used to group * only broadcasts that have a corresponding response event into sessions. */ long getBroadcastSessionsWithResponseDurationMs(); /** * Returns {@code true} if the response event should be attributed to all the broadcast * sessions that occurred within the broadcast response window and {@code false} if the * response event should be attributed to only the earliest broadcast session within the * broadcast response window. */ boolean shouldNoteResponseEventForAllBroadcastSessions(); /** * Return the last known value corresponding to the {@code key} from * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController. Loading apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +81 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,32 @@ public class AppStandbyController volatile int mBroadcastResponseFgThresholdState = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE; /** * Duration (in millis) for the window within which any broadcasts occurred will be * treated as one broadcast session. */ volatile long mBroadcastSessionsDurationMs = ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_DURATION_MS; /** * Duration (in millis) for the window within which any broadcasts occurred ((with a * corresponding response event) will be treated as one broadcast session. This similar to * {@link #mBroadcastSessionsDurationMs}, except that this duration will be used to group only * broadcasts that have a corresponding response event into sessions. */ volatile long mBroadcastSessionsWithResponseDurationMs = ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS; /** * Denotes whether the response event should be attributed to all broadcast sessions or not. * If this is {@code true}, then the response event should be attributed to all the broadcast * sessions that occurred within the broadcast response window. Otherwise, the * response event should be attributed to only the earliest broadcast session within the * broadcast response window. */ volatile boolean mNoteResponseEventForAllBroadcastSessions = ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS; /** * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}. * Loading Loading @@ -1868,6 +1894,21 @@ public class AppStandbyController return mBroadcastResponseFgThresholdState; } @Override public long getBroadcastSessionsDurationMs() { return mBroadcastSessionsDurationMs; } @Override public long getBroadcastSessionsWithResponseDurationMs() { return mBroadcastSessionsWithResponseDurationMs; } @Override public boolean shouldNoteResponseEventForAllBroadcastSessions() { return mNoteResponseEventForAllBroadcastSessions; } @Override @Nullable public String getAppStandbyConstant(@NonNull String key) { Loading Loading @@ -2202,6 +2243,18 @@ public class AppStandbyController pw.print(ActivityManager.procStateToString(mBroadcastResponseFgThresholdState)); pw.println(); pw.print(" mBroadcastSessionsDurationMs="); TimeUtils.formatDuration(mBroadcastSessionsDurationMs, pw); pw.println(); pw.print(" mBroadcastSessionsWithResponseDurationMs="); TimeUtils.formatDuration(mBroadcastSessionsWithResponseDurationMs, pw); pw.println(); pw.print(" mNoteResponseEventForAllBroadcastSessions="); pw.print(mNoteResponseEventForAllBroadcastSessions); pw.println(); pw.println(); pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); pw.print(" mAllowRestrictedBucket="); Loading Loading @@ -2672,6 +2725,13 @@ public class AppStandbyController "broadcast_response_window_timeout_ms"; private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = "broadcast_response_fg_threshold_state"; private static final String KEY_BROADCAST_SESSIONS_DURATION_MS = "broadcast_sessions_duration_ms"; private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = "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"; public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = Loading Loading @@ -2705,6 +2765,12 @@ public class AppStandbyController 2 * ONE_MINUTE; public static final int DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = ActivityManager.PROCESS_STATE_TOP; public static final long DEFAULT_BROADCAST_SESSIONS_DURATION_MS = 2 * ONE_MINUTE; public static final long DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = 2 * ONE_MINUTE; public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = true; ConstantsObserver(Handler handler) { super(handler); Loading Loading @@ -2832,6 +2898,21 @@ public class AppStandbyController KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE, DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE); break; case KEY_BROADCAST_SESSIONS_DURATION_MS: mBroadcastSessionsDurationMs = properties.getLong( KEY_BROADCAST_SESSIONS_DURATION_MS, DEFAULT_BROADCAST_SESSIONS_DURATION_MS); break; case KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS: mBroadcastSessionsWithResponseDurationMs = properties.getLong( KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS, DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS); break; case KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS: mNoteResponseEventForAllBroadcastSessions = properties.getBoolean( KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS, DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS); break; default: if (!timeThresholdsUpdated && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) Loading services/usage/java/com/android/server/usage/BroadcastEvent.java +11 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.usage; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.util.LongArrayQueue; import java.util.Objects; Loading @@ -30,6 +31,7 @@ class BroadcastEvent { private String mTargetPackage; private int mTargetUserId; private long mIdForResponseEvent; private final LongArrayQueue mTimestampsMs; BroadcastEvent(int sourceUid, @NonNull String targetPackage, @UserIdInt int targetUserId, long idForResponseEvent) { Loading @@ -37,6 +39,7 @@ class BroadcastEvent { mTargetPackage = targetPackage; mTargetUserId = targetUserId; mIdForResponseEvent = idForResponseEvent; mTimestampsMs = new LongArrayQueue(); } public int getSourceUid() { Loading @@ -55,6 +58,14 @@ class BroadcastEvent { return mIdForResponseEvent; } public LongArrayQueue getTimestampsMs() { return mTimestampsMs; } public void addTimestampMs(long timestampMs) { mTimestampsMs.addLast(timestampMs); } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { Loading services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +97 −48 Original line number Diff line number Diff line Loading @@ -24,8 +24,10 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager.ProcessState; import android.app.usage.BroadcastResponseStats; import android.os.SystemClock; import android.os.UserHandle; import android.util.LongSparseArray; import android.util.ArraySet; import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseArray; Loading Loading @@ -89,14 +91,14 @@ class BroadcastResponseStatsTracker { return; } synchronized (mLock) { final LongSparseArray<BroadcastEvent> broadcastEvents = final ArraySet<BroadcastEvent> broadcastEvents = getOrCreateBroadcastEventsLocked(targetPackage, targetUser); final BroadcastEvent broadcastEvent = new BroadcastEvent( final BroadcastEvent broadcastEvent = getOrCreateBroadcastEvent(broadcastEvents, sourceUid, targetPackage, targetUser.getIdentifier(), idForResponseEvent); broadcastEvents.append(timestampMs, broadcastEvent); final BroadcastResponseStats responseStats = getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastEvent.addTimestampMs(timestampMs); // Delete any old broadcast event related data so that we don't keep accumulating them. recordAndPruneOldBroadcastDispatchTimestamps(broadcastEvent); } } Loading @@ -120,28 +122,45 @@ class BroadcastResponseStatsTracker { @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { mLogger.logNotificationEvent(event, packageName, user, timestampMs); synchronized (mLock) { final LongSparseArray<BroadcastEvent> broadcastEvents = final ArraySet<BroadcastEvent> broadcastEvents = getBroadcastEventsLocked(packageName, user); if (broadcastEvents == null) { return; } // TODO (206518114): Add LongSparseArray.removeAtRange() final long broadcastResponseWindowDurationMs = mAppStandby.getBroadcastResponseWindowDurationMs(); final long broadcastsSessionWithResponseDurationMs = mAppStandby.getBroadcastSessionsWithResponseDurationMs(); final boolean recordAllBroadcastsSessionsWithinResponseWindow = mAppStandby.shouldNoteResponseEventForAllBroadcastSessions(); for (int i = broadcastEvents.size() - 1; i >= 0; --i) { final long dispatchTimestampMs = broadcastEvents.keyAt(i); final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(i); recordAndPruneOldBroadcastDispatchTimestamps(broadcastEvent); final LongArrayQueue dispatchTimestampsMs = broadcastEvent.getTimestampsMs(); long broadcastsSessionEndTimestampMs = 0; // We only need to look at the broadcast events that occurred before // this notification related event. while (dispatchTimestampsMs.size() > 0 && dispatchTimestampsMs.peekFirst() < timestampMs) { final long dispatchTimestampMs = dispatchTimestampsMs.peekFirst(); final long elapsedDurationMs = timestampMs - dispatchTimestampMs; if (elapsedDurationMs <= 0) { continue; } if (dispatchTimestampMs >= timestampMs) { continue; // Only increment the counts if the broadcast was sent not too long ago, as // decided by 'broadcastResponseWindowDurationMs' and is part of a new session. // That is, it occurred 'broadcastsSessionWithResponseDurationMs' after the // previously handled broadcast event which is represented by // 'broadcastsSessionEndTimestampMs'. if (elapsedDurationMs <= broadcastResponseWindowDurationMs && dispatchTimestampMs >= broadcastsSessionEndTimestampMs) { if (broadcastsSessionEndTimestampMs != 0 && !recordAllBroadcastsSessionsWithinResponseWindow) { break; } if (elapsedDurationMs <= mAppStandby.getBroadcastResponseWindowDurationMs()) { final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(i); final BroadcastResponseStats responseStats = getBroadcastResponseStats(broadcastEvent); if (responseStats == null) { continue; } getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastsSessionEndTimestampMs = dispatchTimestampMs + broadcastsSessionWithResponseDurationMs; switch (event) { case NOTIFICATION_EVENT_TYPE_POSTED: responseStats.incrementNotificationsPostedCount(1); Loading @@ -156,10 +175,36 @@ class BroadcastResponseStatsTracker { Slog.wtf(TAG, "Unknown event: " + event); } } dispatchTimestampsMs.removeFirst(); } if (dispatchTimestampsMs.size() == 0) { broadcastEvents.removeAt(i); } } } } @GuardedBy("mLock") private void recordAndPruneOldBroadcastDispatchTimestamps(BroadcastEvent broadcastEvent) { final LongArrayQueue timestampsMs = broadcastEvent.getTimestampsMs(); final long broadcastResponseWindowDurationMs = mAppStandby.getBroadcastResponseWindowDurationMs(); final long broadcastsSessionDurationMs = mAppStandby.getBroadcastSessionsDurationMs(); final long nowElapsedMs = SystemClock.elapsedRealtime(); long broadcastsSessionEndTimestampMs = 0; while (timestampsMs.size() > 0 && timestampsMs.peekFirst() < (nowElapsedMs - broadcastResponseWindowDurationMs)) { final long eventTimestampMs = timestampsMs.peekFirst(); if (eventTimestampMs >= broadcastsSessionEndTimestampMs) { final BroadcastResponseStats responseStats = getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastsSessionEndTimestampMs = eventTimestampMs + broadcastsSessionDurationMs; } timestampsMs.removeFirst(); } } @NonNull List<BroadcastResponseStats> queryBroadcastResponseStats(int callingUid, @Nullable String packageName, @IntRange(from = 0) long id, @UserIdInt int userId) { Loading Loading @@ -247,7 +292,7 @@ class BroadcastResponseStatsTracker { @GuardedBy("mLock") @Nullable private LongSparseArray<BroadcastEvent> getBroadcastEventsLocked( private ArraySet<BroadcastEvent> getBroadcastEventsLocked( @NonNull String packageName, UserHandle user) { final UserBroadcastEvents userBroadcastEvents = mUserBroadcastEvents.get( user.getIdentifier()); Loading @@ -259,7 +304,7 @@ class BroadcastResponseStatsTracker { @GuardedBy("mLock") @NonNull private LongSparseArray<BroadcastEvent> getOrCreateBroadcastEventsLocked( private ArraySet<BroadcastEvent> getOrCreateBroadcastEventsLocked( @NonNull String packageName, UserHandle user) { UserBroadcastEvents userBroadcastEvents = mUserBroadcastEvents.get(user.getIdentifier()); if (userBroadcastEvents == null) { Loading @@ -269,16 +314,6 @@ class BroadcastResponseStatsTracker { return userBroadcastEvents.getOrCreateBroadcastEvents(packageName); } @GuardedBy("mLock") @Nullable private BroadcastResponseStats getBroadcastResponseStats( @NonNull BroadcastEvent broadcastEvent) { final int sourceUid = broadcastEvent.getSourceUid(); final SparseArray<UserBroadcastResponseStats> responseStatsForUid = mUserResponseStats.get(sourceUid); return getBroadcastResponseStats(responseStatsForUid, broadcastEvent); } @GuardedBy("mLock") @Nullable private BroadcastResponseStats getBroadcastResponseStats( Loading Loading @@ -315,6 +350,20 @@ class BroadcastResponseStatsTracker { return userResponseStats.getOrCreateBroadcastResponseStats(broadcastEvent); } private static BroadcastEvent getOrCreateBroadcastEvent( ArraySet<BroadcastEvent> broadcastEvents, int sourceUid, String targetPackage, int targetUserId, long idForResponseEvent) { final BroadcastEvent broadcastEvent = new BroadcastEvent( sourceUid, targetPackage, targetUserId, idForResponseEvent); final int index = broadcastEvents.indexOf(broadcastEvent); if (index >= 0) { return broadcastEvents.valueAt(index); } else { broadcastEvents.add(broadcastEvent); return broadcastEvent; } } void dump(@NonNull IndentingPrintWriter ipw) { ipw.println("Broadcast response stats:"); ipw.increaseIndent(); Loading services/usage/java/com/android/server/usage/UserBroadcastEvents.java +20 −11 Original line number Diff line number Diff line Loading @@ -19,7 +19,8 @@ package com.android.server.usage; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.LongSparseArray; import android.util.ArraySet; import android.util.LongArrayQueue; import android.util.TimeUtils; import com.android.internal.util.IndentingPrintWriter; Loading @@ -30,17 +31,17 @@ class UserBroadcastEvents { * Here targetPackage refers to the package receiving the broadcast and BroadcastEvent objects * corresponding to each broadcast it is receiving. */ private ArrayMap<String, LongSparseArray<BroadcastEvent>> mBroadcastEvents = new ArrayMap(); private ArrayMap<String, ArraySet<BroadcastEvent>> mBroadcastEvents = new ArrayMap(); @Nullable LongSparseArray<BroadcastEvent> getBroadcastEvents(@NonNull String packageName) { @Nullable ArraySet<BroadcastEvent> getBroadcastEvents(@NonNull String packageName) { return mBroadcastEvents.get(packageName); } @NonNull LongSparseArray<BroadcastEvent> getOrCreateBroadcastEvents( @NonNull ArraySet<BroadcastEvent> getOrCreateBroadcastEvents( @NonNull String packageName) { LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.get(packageName); ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.get(packageName); if (broadcastEvents == null) { broadcastEvents = new LongSparseArray<>(); broadcastEvents = new ArraySet<>(); mBroadcastEvents.put(packageName, broadcastEvents); } return broadcastEvents; Loading @@ -56,7 +57,7 @@ class UserBroadcastEvents { void clear(int uid) { for (int i = mBroadcastEvents.size() - 1; i >= 0; --i) { final LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); final ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); for (int j = broadcastEvents.size() - 1; j >= 0; --j) { if (broadcastEvents.valueAt(j).getSourceUid() == uid) { broadcastEvents.removeAt(j); Loading @@ -68,18 +69,26 @@ class UserBroadcastEvents { void dump(@NonNull IndentingPrintWriter ipw) { for (int i = 0; i < mBroadcastEvents.size(); ++i) { final String packageName = mBroadcastEvents.keyAt(i); final LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); final ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); ipw.println(packageName + ":"); ipw.increaseIndent(); if (broadcastEvents.size() == 0) { ipw.println("<empty>"); } else { for (int j = 0; j < broadcastEvents.size(); ++j) { final long timestampMs = broadcastEvents.keyAt(j); final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(j); TimeUtils.formatDuration(timestampMs, ipw); ipw.print(": "); ipw.println(broadcastEvent); ipw.increaseIndent(); final LongArrayQueue timestampsMs = broadcastEvent.getTimestampsMs(); for (int timestampIdx = 0; timestampIdx < timestampsMs.size(); ++timestampIdx) { if (timestampIdx > 0) { ipw.print(','); } final long timestampMs = timestampsMs.get(timestampIdx); TimeUtils.formatDuration(timestampMs, ipw); } ipw.println(); ipw.decreaseIndent(); } } ipw.decreaseIndent(); Loading Loading
apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +22 −0 Original line number Diff line number Diff line Loading @@ -246,6 +246,28 @@ public interface AppStandbyInternal { @ProcessState int getBroadcastResponseFgThresholdState(); /** * Returns the duration within which any broadcasts occurred will be treated as one broadcast * session. */ long getBroadcastSessionsDurationMs(); /** * Returns the duration within which any broadcasts occurred (with a corresponding response * event) will be treated as one broadcast session. This similar to * {@link #getBroadcastSessionsDurationMs()}, except that this duration will be used to group * only broadcasts that have a corresponding response event into sessions. */ long getBroadcastSessionsWithResponseDurationMs(); /** * Returns {@code true} if the response event should be attributed to all the broadcast * sessions that occurred within the broadcast response window and {@code false} if the * response event should be attributed to only the earliest broadcast session within the * broadcast response window. */ boolean shouldNoteResponseEventForAllBroadcastSessions(); /** * Return the last known value corresponding to the {@code key} from * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController. Loading
apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +81 −0 Original line number Diff line number Diff line Loading @@ -376,6 +376,32 @@ public class AppStandbyController volatile int mBroadcastResponseFgThresholdState = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE; /** * Duration (in millis) for the window within which any broadcasts occurred will be * treated as one broadcast session. */ volatile long mBroadcastSessionsDurationMs = ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_DURATION_MS; /** * Duration (in millis) for the window within which any broadcasts occurred ((with a * corresponding response event) will be treated as one broadcast session. This similar to * {@link #mBroadcastSessionsDurationMs}, except that this duration will be used to group only * broadcasts that have a corresponding response event into sessions. */ volatile long mBroadcastSessionsWithResponseDurationMs = ConstantsObserver.DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS; /** * Denotes whether the response event should be attributed to all broadcast sessions or not. * If this is {@code true}, then the response event should be attributed to all the broadcast * sessions that occurred within the broadcast response window. Otherwise, the * response event should be attributed to only the earliest broadcast session within the * broadcast response window. */ volatile boolean mNoteResponseEventForAllBroadcastSessions = ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS; /** * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}. * Loading Loading @@ -1868,6 +1894,21 @@ public class AppStandbyController return mBroadcastResponseFgThresholdState; } @Override public long getBroadcastSessionsDurationMs() { return mBroadcastSessionsDurationMs; } @Override public long getBroadcastSessionsWithResponseDurationMs() { return mBroadcastSessionsWithResponseDurationMs; } @Override public boolean shouldNoteResponseEventForAllBroadcastSessions() { return mNoteResponseEventForAllBroadcastSessions; } @Override @Nullable public String getAppStandbyConstant(@NonNull String key) { Loading Loading @@ -2202,6 +2243,18 @@ public class AppStandbyController pw.print(ActivityManager.procStateToString(mBroadcastResponseFgThresholdState)); pw.println(); pw.print(" mBroadcastSessionsDurationMs="); TimeUtils.formatDuration(mBroadcastSessionsDurationMs, pw); pw.println(); pw.print(" mBroadcastSessionsWithResponseDurationMs="); TimeUtils.formatDuration(mBroadcastSessionsWithResponseDurationMs, pw); pw.println(); pw.print(" mNoteResponseEventForAllBroadcastSessions="); pw.print(mNoteResponseEventForAllBroadcastSessions); pw.println(); pw.println(); pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); pw.print(" mAllowRestrictedBucket="); Loading Loading @@ -2672,6 +2725,13 @@ public class AppStandbyController "broadcast_response_window_timeout_ms"; private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = "broadcast_response_fg_threshold_state"; private static final String KEY_BROADCAST_SESSIONS_DURATION_MS = "broadcast_sessions_duration_ms"; private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = "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"; public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = Loading Loading @@ -2705,6 +2765,12 @@ public class AppStandbyController 2 * ONE_MINUTE; public static final int DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = ActivityManager.PROCESS_STATE_TOP; public static final long DEFAULT_BROADCAST_SESSIONS_DURATION_MS = 2 * ONE_MINUTE; public static final long DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS = 2 * ONE_MINUTE; public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = true; ConstantsObserver(Handler handler) { super(handler); Loading Loading @@ -2832,6 +2898,21 @@ public class AppStandbyController KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE, DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE); break; case KEY_BROADCAST_SESSIONS_DURATION_MS: mBroadcastSessionsDurationMs = properties.getLong( KEY_BROADCAST_SESSIONS_DURATION_MS, DEFAULT_BROADCAST_SESSIONS_DURATION_MS); break; case KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS: mBroadcastSessionsWithResponseDurationMs = properties.getLong( KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS, DEFAULT_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS); break; case KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS: mNoteResponseEventForAllBroadcastSessions = properties.getBoolean( KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS, DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS); break; default: if (!timeThresholdsUpdated && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) Loading
services/usage/java/com/android/server/usage/BroadcastEvent.java +11 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.usage; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.util.LongArrayQueue; import java.util.Objects; Loading @@ -30,6 +31,7 @@ class BroadcastEvent { private String mTargetPackage; private int mTargetUserId; private long mIdForResponseEvent; private final LongArrayQueue mTimestampsMs; BroadcastEvent(int sourceUid, @NonNull String targetPackage, @UserIdInt int targetUserId, long idForResponseEvent) { Loading @@ -37,6 +39,7 @@ class BroadcastEvent { mTargetPackage = targetPackage; mTargetUserId = targetUserId; mIdForResponseEvent = idForResponseEvent; mTimestampsMs = new LongArrayQueue(); } public int getSourceUid() { Loading @@ -55,6 +58,14 @@ class BroadcastEvent { return mIdForResponseEvent; } public LongArrayQueue getTimestampsMs() { return mTimestampsMs; } public void addTimestampMs(long timestampMs) { mTimestampsMs.addLast(timestampMs); } @Override public boolean equals(@Nullable Object obj) { if (this == obj) { Loading
services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +97 −48 Original line number Diff line number Diff line Loading @@ -24,8 +24,10 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager.ProcessState; import android.app.usage.BroadcastResponseStats; import android.os.SystemClock; import android.os.UserHandle; import android.util.LongSparseArray; import android.util.ArraySet; import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseArray; Loading Loading @@ -89,14 +91,14 @@ class BroadcastResponseStatsTracker { return; } synchronized (mLock) { final LongSparseArray<BroadcastEvent> broadcastEvents = final ArraySet<BroadcastEvent> broadcastEvents = getOrCreateBroadcastEventsLocked(targetPackage, targetUser); final BroadcastEvent broadcastEvent = new BroadcastEvent( final BroadcastEvent broadcastEvent = getOrCreateBroadcastEvent(broadcastEvents, sourceUid, targetPackage, targetUser.getIdentifier(), idForResponseEvent); broadcastEvents.append(timestampMs, broadcastEvent); final BroadcastResponseStats responseStats = getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastEvent.addTimestampMs(timestampMs); // Delete any old broadcast event related data so that we don't keep accumulating them. recordAndPruneOldBroadcastDispatchTimestamps(broadcastEvent); } } Loading @@ -120,28 +122,45 @@ class BroadcastResponseStatsTracker { @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { mLogger.logNotificationEvent(event, packageName, user, timestampMs); synchronized (mLock) { final LongSparseArray<BroadcastEvent> broadcastEvents = final ArraySet<BroadcastEvent> broadcastEvents = getBroadcastEventsLocked(packageName, user); if (broadcastEvents == null) { return; } // TODO (206518114): Add LongSparseArray.removeAtRange() final long broadcastResponseWindowDurationMs = mAppStandby.getBroadcastResponseWindowDurationMs(); final long broadcastsSessionWithResponseDurationMs = mAppStandby.getBroadcastSessionsWithResponseDurationMs(); final boolean recordAllBroadcastsSessionsWithinResponseWindow = mAppStandby.shouldNoteResponseEventForAllBroadcastSessions(); for (int i = broadcastEvents.size() - 1; i >= 0; --i) { final long dispatchTimestampMs = broadcastEvents.keyAt(i); final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(i); recordAndPruneOldBroadcastDispatchTimestamps(broadcastEvent); final LongArrayQueue dispatchTimestampsMs = broadcastEvent.getTimestampsMs(); long broadcastsSessionEndTimestampMs = 0; // We only need to look at the broadcast events that occurred before // this notification related event. while (dispatchTimestampsMs.size() > 0 && dispatchTimestampsMs.peekFirst() < timestampMs) { final long dispatchTimestampMs = dispatchTimestampsMs.peekFirst(); final long elapsedDurationMs = timestampMs - dispatchTimestampMs; if (elapsedDurationMs <= 0) { continue; } if (dispatchTimestampMs >= timestampMs) { continue; // Only increment the counts if the broadcast was sent not too long ago, as // decided by 'broadcastResponseWindowDurationMs' and is part of a new session. // That is, it occurred 'broadcastsSessionWithResponseDurationMs' after the // previously handled broadcast event which is represented by // 'broadcastsSessionEndTimestampMs'. if (elapsedDurationMs <= broadcastResponseWindowDurationMs && dispatchTimestampMs >= broadcastsSessionEndTimestampMs) { if (broadcastsSessionEndTimestampMs != 0 && !recordAllBroadcastsSessionsWithinResponseWindow) { break; } if (elapsedDurationMs <= mAppStandby.getBroadcastResponseWindowDurationMs()) { final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(i); final BroadcastResponseStats responseStats = getBroadcastResponseStats(broadcastEvent); if (responseStats == null) { continue; } getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastsSessionEndTimestampMs = dispatchTimestampMs + broadcastsSessionWithResponseDurationMs; switch (event) { case NOTIFICATION_EVENT_TYPE_POSTED: responseStats.incrementNotificationsPostedCount(1); Loading @@ -156,10 +175,36 @@ class BroadcastResponseStatsTracker { Slog.wtf(TAG, "Unknown event: " + event); } } dispatchTimestampsMs.removeFirst(); } if (dispatchTimestampsMs.size() == 0) { broadcastEvents.removeAt(i); } } } } @GuardedBy("mLock") private void recordAndPruneOldBroadcastDispatchTimestamps(BroadcastEvent broadcastEvent) { final LongArrayQueue timestampsMs = broadcastEvent.getTimestampsMs(); final long broadcastResponseWindowDurationMs = mAppStandby.getBroadcastResponseWindowDurationMs(); final long broadcastsSessionDurationMs = mAppStandby.getBroadcastSessionsDurationMs(); final long nowElapsedMs = SystemClock.elapsedRealtime(); long broadcastsSessionEndTimestampMs = 0; while (timestampsMs.size() > 0 && timestampsMs.peekFirst() < (nowElapsedMs - broadcastResponseWindowDurationMs)) { final long eventTimestampMs = timestampsMs.peekFirst(); if (eventTimestampMs >= broadcastsSessionEndTimestampMs) { final BroadcastResponseStats responseStats = getOrCreateBroadcastResponseStats(broadcastEvent); responseStats.incrementBroadcastsDispatchedCount(1); broadcastsSessionEndTimestampMs = eventTimestampMs + broadcastsSessionDurationMs; } timestampsMs.removeFirst(); } } @NonNull List<BroadcastResponseStats> queryBroadcastResponseStats(int callingUid, @Nullable String packageName, @IntRange(from = 0) long id, @UserIdInt int userId) { Loading Loading @@ -247,7 +292,7 @@ class BroadcastResponseStatsTracker { @GuardedBy("mLock") @Nullable private LongSparseArray<BroadcastEvent> getBroadcastEventsLocked( private ArraySet<BroadcastEvent> getBroadcastEventsLocked( @NonNull String packageName, UserHandle user) { final UserBroadcastEvents userBroadcastEvents = mUserBroadcastEvents.get( user.getIdentifier()); Loading @@ -259,7 +304,7 @@ class BroadcastResponseStatsTracker { @GuardedBy("mLock") @NonNull private LongSparseArray<BroadcastEvent> getOrCreateBroadcastEventsLocked( private ArraySet<BroadcastEvent> getOrCreateBroadcastEventsLocked( @NonNull String packageName, UserHandle user) { UserBroadcastEvents userBroadcastEvents = mUserBroadcastEvents.get(user.getIdentifier()); if (userBroadcastEvents == null) { Loading @@ -269,16 +314,6 @@ class BroadcastResponseStatsTracker { return userBroadcastEvents.getOrCreateBroadcastEvents(packageName); } @GuardedBy("mLock") @Nullable private BroadcastResponseStats getBroadcastResponseStats( @NonNull BroadcastEvent broadcastEvent) { final int sourceUid = broadcastEvent.getSourceUid(); final SparseArray<UserBroadcastResponseStats> responseStatsForUid = mUserResponseStats.get(sourceUid); return getBroadcastResponseStats(responseStatsForUid, broadcastEvent); } @GuardedBy("mLock") @Nullable private BroadcastResponseStats getBroadcastResponseStats( Loading Loading @@ -315,6 +350,20 @@ class BroadcastResponseStatsTracker { return userResponseStats.getOrCreateBroadcastResponseStats(broadcastEvent); } private static BroadcastEvent getOrCreateBroadcastEvent( ArraySet<BroadcastEvent> broadcastEvents, int sourceUid, String targetPackage, int targetUserId, long idForResponseEvent) { final BroadcastEvent broadcastEvent = new BroadcastEvent( sourceUid, targetPackage, targetUserId, idForResponseEvent); final int index = broadcastEvents.indexOf(broadcastEvent); if (index >= 0) { return broadcastEvents.valueAt(index); } else { broadcastEvents.add(broadcastEvent); return broadcastEvent; } } void dump(@NonNull IndentingPrintWriter ipw) { ipw.println("Broadcast response stats:"); ipw.increaseIndent(); Loading
services/usage/java/com/android/server/usage/UserBroadcastEvents.java +20 −11 Original line number Diff line number Diff line Loading @@ -19,7 +19,8 @@ package com.android.server.usage; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.LongSparseArray; import android.util.ArraySet; import android.util.LongArrayQueue; import android.util.TimeUtils; import com.android.internal.util.IndentingPrintWriter; Loading @@ -30,17 +31,17 @@ class UserBroadcastEvents { * Here targetPackage refers to the package receiving the broadcast and BroadcastEvent objects * corresponding to each broadcast it is receiving. */ private ArrayMap<String, LongSparseArray<BroadcastEvent>> mBroadcastEvents = new ArrayMap(); private ArrayMap<String, ArraySet<BroadcastEvent>> mBroadcastEvents = new ArrayMap(); @Nullable LongSparseArray<BroadcastEvent> getBroadcastEvents(@NonNull String packageName) { @Nullable ArraySet<BroadcastEvent> getBroadcastEvents(@NonNull String packageName) { return mBroadcastEvents.get(packageName); } @NonNull LongSparseArray<BroadcastEvent> getOrCreateBroadcastEvents( @NonNull ArraySet<BroadcastEvent> getOrCreateBroadcastEvents( @NonNull String packageName) { LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.get(packageName); ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.get(packageName); if (broadcastEvents == null) { broadcastEvents = new LongSparseArray<>(); broadcastEvents = new ArraySet<>(); mBroadcastEvents.put(packageName, broadcastEvents); } return broadcastEvents; Loading @@ -56,7 +57,7 @@ class UserBroadcastEvents { void clear(int uid) { for (int i = mBroadcastEvents.size() - 1; i >= 0; --i) { final LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); final ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); for (int j = broadcastEvents.size() - 1; j >= 0; --j) { if (broadcastEvents.valueAt(j).getSourceUid() == uid) { broadcastEvents.removeAt(j); Loading @@ -68,18 +69,26 @@ class UserBroadcastEvents { void dump(@NonNull IndentingPrintWriter ipw) { for (int i = 0; i < mBroadcastEvents.size(); ++i) { final String packageName = mBroadcastEvents.keyAt(i); final LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); final ArraySet<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i); ipw.println(packageName + ":"); ipw.increaseIndent(); if (broadcastEvents.size() == 0) { ipw.println("<empty>"); } else { for (int j = 0; j < broadcastEvents.size(); ++j) { final long timestampMs = broadcastEvents.keyAt(j); final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(j); TimeUtils.formatDuration(timestampMs, ipw); ipw.print(": "); ipw.println(broadcastEvent); ipw.increaseIndent(); final LongArrayQueue timestampsMs = broadcastEvent.getTimestampsMs(); for (int timestampIdx = 0; timestampIdx < timestampsMs.size(); ++timestampIdx) { if (timestampIdx > 0) { ipw.print(','); } final long timestampMs = timestampsMs.get(timestampIdx); TimeUtils.formatDuration(timestampMs, ipw); } ipw.println(); ipw.decreaseIndent(); } } ipw.decreaseIndent(); Loading