From d1e5fabaa925ee18019a2869b029ef017ec26817 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Fri, 28 Jan 2022 16:24:07 -0800 Subject: [PATCH 1/2] Track broadcast dispatched event only when the app is in the bg. Bug: 206518114 Test: atest tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java Change-Id: Ic017fff35d800a1ea9b4288421e021859f443b30 --- .../app/usage/UsageStatsManagerInternal.java | 4 +++- .../com/android/server/am/BroadcastQueue.java | 11 +++++------ .../usage/BroadcastResponseStatsTracker.java | 18 ++++++++++++++---- .../server/usage/UsageStatsService.java | 5 +++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java index 435d294a3e8e0..a35aa7c74ee5a 100644 --- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -21,6 +21,7 @@ import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityManager.ProcessState; import android.app.usage.UsageStatsManager.StandbyBuckets; import android.content.ComponentName; import android.content.LocusId; @@ -375,10 +376,11 @@ public abstract class UsageStatsManagerInternal { * to this broadcast. * @param timestampMs time (in millis) when the broadcast was dispatched, in * {@link SystemClock#elapsedRealtime()} timebase. + * @param targetUidProcState process state of the uid that the broadcast is targeted to. */ public abstract void reportBroadcastDispatched(int sourceUid, @NonNull String targetPackage, @NonNull UserHandle targetUser, long idForResponseEvent, - @ElapsedRealtimeLong long timestampMs); + @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState); /** * Reports a notification posted event to the UsageStatsManager. diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 0c383ebbbcd70..e2921e9f5e71d 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -334,7 +334,7 @@ public final class BroadcastQueue { mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER); // Tell the application to launch this receiver. - maybeReportBroadcastDispatchedEventLocked(r); + maybeReportBroadcastDispatchedEventLocked(r, r.curReceiver.applicationInfo.uid); r.intent.setComponent(r.curComponent); boolean started = false; @@ -927,7 +927,7 @@ public final class BroadcastQueue { r.receiverTime = SystemClock.uptimeMillis(); maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r); maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options); - maybeReportBroadcastDispatchedEventLocked(r); + maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid); performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId); @@ -1856,7 +1856,7 @@ public final class BroadcastQueue { return null; } - private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r) { + private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) { final String targetPackage = getTargetPackage(r); // Ignore non-explicit broadcasts if (targetPackage == null) { @@ -1867,11 +1867,10 @@ public final class BroadcastQueue { if (r.options == null || r.options.getIdForResponseEvent() <= 0) { return; } - // TODO (206518114): Only report this event when the broadcast is dispatched while the app - // is in the background state. getUsageStatsManagerInternal().reportBroadcastDispatched( r.callingUid, targetPackage, UserHandle.of(r.userId), - r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime()); + r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime(), + mService.getUidStateLocked(targetUid)); } @NonNull diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java index e65501329cdfe..795018436ec01 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java @@ -16,6 +16,9 @@ package com.android.server.usage; +import static android.app.ActivityManager.PROCESS_STATE_TOP; +import static android.app.ActivityManager.procStateToString; + import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; import android.annotation.ElapsedRealtimeLong; @@ -23,6 +26,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityManager.ProcessState; import android.app.usage.BroadcastResponseStats; import android.os.UserHandle; import android.text.TextUtils; @@ -78,12 +82,18 @@ class BroadcastResponseStatsTracker { // TODO (206518114): Move all callbacks handling to a handler thread. void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, - @ElapsedRealtimeLong long timestampMs) { + @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { if (DEBUG_RESPONSE_STATS) { - Slog.d(TAG, TextUtils.formatSimple( - "reportBroadcastDispatchEvent; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s", + Slog.d(TAG, TextUtils.formatSimple("reportBroadcastDispatchEvent; " + + "srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s, state=%s", sourceUid, targetPackage, targetUser, idForResponseEvent, - TimeUtils.formatDuration(timestampMs))); + TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState))); + } + // TODO (206518114): Make the fg threshold state configurable. + if (targetUidProcState <= PROCESS_STATE_TOP) { + // No need to track the broadcast response state while the target app is + // in the foreground. + return; } synchronized (mLock) { final LongSparseArray broadcastEvents = diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 6906f20f26c2a..98a41bcf5adfd 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -42,6 +42,7 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.ActivityManager.ProcessState; import android.app.AppOpsManager; import android.app.IUidObserver; import android.app.PendingIntent; @@ -3042,9 +3043,9 @@ public class UsageStatsService extends SystemService implements @Override public void reportBroadcastDispatched(int sourceUid, @NonNull String targetPackage, @NonNull UserHandle targetUser, long idForResponseEvent, - @ElapsedRealtimeLong long timestampMs) { + @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { mResponseStatsTracker.reportBroadcastDispatchEvent(sourceUid, targetPackage, - targetUser, idForResponseEvent, timestampMs); + targetUser, idForResponseEvent, timestampMs, targetUidProcState); } @Override From 918d72438648ee7309e76020dc2a1d4d7e8457b5 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Fri, 28 Jan 2022 18:32:47 -0800 Subject: [PATCH 2/2] Make broadcast response fg threshold state configurable. Bug: 206518114 Test: atest tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java Change-Id: Ic28b25393b8ff7d50164535722567d1a4e34f102 --- .../server/usage/AppStandbyInternal.java | 9 +++++++ .../server/usage/AppStandbyController.java | 26 +++++++++++++++++++ .../usage/BroadcastResponseStatsTracker.java | 4 +-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index ddcc74696d94c..13ecd25d429ab 100644 --- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -3,6 +3,7 @@ package com.android.server.usage; import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; import android.annotation.UserIdInt; +import android.app.ActivityManager.ProcessState; import android.app.usage.AppStandbyInfo; import android.app.usage.UsageStatsManager.ForcedReasons; import android.app.usage.UsageStatsManager.StandbyBuckets; @@ -223,4 +224,12 @@ public interface AppStandbyInternal { * a broadcast. */ long getBroadcastResponseWindowDurationMs(); + + /** + * Returns the process state threshold that should be used for deciding whether or not an app + * is in the background in the context of recording broadcast response stats. Apps whose + * process state is higher than this threshold state should be considered to be in background. + */ + @ProcessState + int getBroadcastResponseFgThresholdState(); } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 050e3df5b5e12..b843dcaaf680b 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -355,6 +355,14 @@ public class AppStandbyController volatile long mBroadcastResponseWindowDurationMillis = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS; + /** + * Process state threshold that is used for deciding whether or not an app is in the background + * in the context of recording broadcast response stats. Apps whose process state is higher + * than this threshold state will be considered to be in background. + */ + volatile int mBroadcastResponseFgThresholdState = + ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE; + /** * Whether we should allow apps into the * {@link android.app.usage.UsageStatsManager#STANDBY_BUCKET_RESTRICTED} bucket or not. @@ -1787,6 +1795,11 @@ public class AppStandbyController return mBroadcastResponseWindowDurationMillis; } + @Override + public int getBroadcastResponseFgThresholdState() { + return mBroadcastResponseFgThresholdState; + } + @Override public void flushToDisk() { synchronized (mAppIdleLock) { @@ -2058,6 +2071,10 @@ public class AppStandbyController TimeUtils.formatDuration(mBroadcastResponseWindowDurationMillis, pw); pw.println(); + pw.print(" mBroadcastResponseFgThresholdState="); + pw.print(ActivityManager.procStateToString(mBroadcastResponseFgThresholdState)); + pw.println(); + pw.println(); pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); pw.print(" mAllowRestrictedBucket="); @@ -2491,6 +2508,8 @@ public class AppStandbyController }; private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS = "broadcast_response_window_timeout_ms"; + private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = + "broadcast_response_fg_threshold_state"; public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; public static final long DEFAULT_STRONG_USAGE_TIMEOUT = @@ -2522,6 +2541,8 @@ public class AppStandbyController public static final boolean DEFAULT_CROSS_PROFILE_APPS_SHARE_STANDBY_BUCKETS = true; public static final long DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS = 2 * ONE_MINUTE; + public static final int DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE = + ActivityManager.PROCESS_STATE_TOP; ConstantsObserver(Handler handler) { super(handler); @@ -2644,6 +2665,11 @@ public class AppStandbyController KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS, DEFAULT_BROADCAST_RESPONSE_WINDOW_DURATION_MS); break; + case KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE: + mBroadcastResponseFgThresholdState = properties.getInt( + KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE, + DEFAULT_BROADCAST_RESPONSE_FG_THRESHOLD_STATE); + break; default: if (!timeThresholdsUpdated && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java index 795018436ec01..27e8d69aa7625 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java @@ -16,7 +16,6 @@ package com.android.server.usage; -import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManager.procStateToString; import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; @@ -89,8 +88,7 @@ class BroadcastResponseStatsTracker { sourceUid, targetPackage, targetUser, idForResponseEvent, TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState))); } - // TODO (206518114): Make the fg threshold state configurable. - if (targetUidProcState <= PROCESS_STATE_TOP) { + if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) { // No need to track the broadcast response state while the target app is // in the foreground. return;