Merge "Group broadcasts occurred within a certain duration into sessions." into tm-dev am: 0a790c6419

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

Change-Id: Id7ea48dd33a65b94d0f611c78c62342fa4d51bc0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sudheer Shanka
2022-05-18 20:52:26 +00:00
committed by Automerger Merge Worker
5 changed files with 232 additions and 60 deletions

View File

@@ -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.

View File

@@ -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}.
*
@@ -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) {
@@ -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=");
@@ -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 =
@@ -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);
@@ -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)

View File

@@ -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;
@@ -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) {
@@ -37,6 +39,7 @@ class BroadcastEvent {
mTargetPackage = targetPackage;
mTargetUserId = targetUserId;
mIdForResponseEvent = idForResponseEvent;
mTimestampsMs = new LongArrayQueue();
}
public int getSourceUid() {
@@ -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) {

View File

@@ -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;
@@ -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);
}
}
@@ -120,47 +122,90 @@ 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 long elapsedDurationMs = timestampMs - dispatchTimestampMs;
if (elapsedDurationMs <= 0) {
continue;
}
if (dispatchTimestampMs >= timestampMs) {
continue;
}
if (elapsedDurationMs <= mAppStandby.getBroadcastResponseWindowDurationMs()) {
final BroadcastEvent broadcastEvent = broadcastEvents.valueAt(i);
final BroadcastResponseStats responseStats =
getBroadcastResponseStats(broadcastEvent);
if (responseStats == null) {
continue;
}
switch (event) {
case NOTIFICATION_EVENT_TYPE_POSTED:
responseStats.incrementNotificationsPostedCount(1);
break;
case NOTIFICATION_EVENT_TYPE_UPDATED:
responseStats.incrementNotificationsUpdatedCount(1);
break;
case NOTIFICATION_EVENT_TYPE_CANCELLED:
responseStats.incrementNotificationsCancelledCount(1);
break;
default:
Slog.wtf(TAG, "Unknown event: " + event);
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;
// 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;
}
final BroadcastResponseStats responseStats =
getOrCreateBroadcastResponseStats(broadcastEvent);
responseStats.incrementBroadcastsDispatchedCount(1);
broadcastsSessionEndTimestampMs = dispatchTimestampMs
+ broadcastsSessionWithResponseDurationMs;
switch (event) {
case NOTIFICATION_EVENT_TYPE_POSTED:
responseStats.incrementNotificationsPostedCount(1);
break;
case NOTIFICATION_EVENT_TYPE_UPDATED:
responseStats.incrementNotificationsUpdatedCount(1);
break;
case NOTIFICATION_EVENT_TYPE_CANCELLED:
responseStats.incrementNotificationsCancelledCount(1);
break;
default:
Slog.wtf(TAG, "Unknown event: " + event);
}
}
dispatchTimestampsMs.removeFirst();
}
if (dispatchTimestampsMs.size() == 0) {
broadcastEvents.removeAt(i);
}
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) {
final List<BroadcastResponseStats> broadcastResponseStatsList = new ArrayList<>();
@@ -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());
@@ -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) {
@@ -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(
@@ -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();

View File

@@ -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;
@@ -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;
@@ -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);
@@ -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();