Avoid multiple calls to start/stop FGS for the same session record
Shouldn't be an issue, as they should both be idempotent operations, but
following the principle of robustness, this CL avoids calling
startingFGSDelegate (or stop) multiple times in a row for the same
session.
Bug: b/295518668
Test: atest CtsMediaBetterTogetherTestCases
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsDelegateTest.java
Flag: com.android.media.flags.enable_notifying_activity_manager_with_media_session_status_change
Change-Id: Ie4a4d2e3b49329f5c4480f1ca4c2531b86fe39a2
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index f02a3ff..1ebc856 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -197,6 +197,16 @@
@GuardedBy("mLock")
private final Map<Integer, Set<Notification>> mMediaNotifications = new HashMap<>();
+ /**
+ * Holds all {@link MediaSessionRecordImpl} which we've reported as being {@link
+ * ActivityManagerInternal#startForegroundServiceDelegate user engaged}.
+ *
+ * <p>This map simply prevents invoking {@link
+ * ActivityManagerInternal#startForegroundServiceDelegate} more than once per session.
+ */
+ @GuardedBy("mLock")
+ private final Set<MediaSessionRecordImpl> mFgsAllowedMediaSessionRecords = new HashSet<>();
+
// The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
// It's always not null after the MediaSessionService is started.
private FullUserRecord mCurrentFullUserRecord;
@@ -704,15 +714,23 @@
int uid = mediaSessionRecord.getUid();
for (Notification mediaNotification : mMediaNotifications.getOrDefault(uid, Set.of())) {
if (mediaSessionRecord.isLinkedToNotification(mediaNotification)) {
- startFgsDelegate(mediaSessionRecord.getForegroundServiceDelegationOptions());
+ startFgsDelegateLocked(mediaSessionRecord);
return;
}
}
}
}
- private void startFgsDelegate(
- ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) {
+ @GuardedBy("mLock")
+ private void startFgsDelegateLocked(MediaSessionRecordImpl mediaSessionRecord) {
+ ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
+ mediaSessionRecord.getForegroundServiceDelegationOptions();
+ if (foregroundServiceDelegationOptions == null) {
+ return; // This record doesn't support FGS. Typically a MediaSession2 record.
+ }
+ if (!mFgsAllowedMediaSessionRecords.add(mediaSessionRecord)) {
+ return; // This record is already FGS-started.
+ }
final long token = Binder.clearCallingIdentity();
try {
Log.i(
@@ -754,12 +772,21 @@
}
}
- stopFgsDelegate(foregroundServiceDelegationOptions);
+ stopFgsDelegateLocked(mediaSessionRecord);
}
}
- private void stopFgsDelegate(
- ForegroundServiceDelegationOptions foregroundServiceDelegationOptions) {
+ @GuardedBy("mLock")
+ private void stopFgsDelegateLocked(MediaSessionRecordImpl mediaSessionRecord) {
+ ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
+ mediaSessionRecord.getForegroundServiceDelegationOptions();
+ if (foregroundServiceDelegationOptions == null) {
+ return; // This record doesn't support FGS. Typically a MediaSession2 record.
+ }
+ if (!mFgsAllowedMediaSessionRecords.remove(mediaSessionRecord)) {
+ return; // This record is not FGS-started. No need to stop it.
+ }
+
final long token = Binder.clearCallingIdentity();
try {
Log.i(
@@ -3209,11 +3236,8 @@
mMediaNotifications.get(uid).add(postedNotification);
for (MediaSessionRecordImpl mediaSessionRecord :
mUserEngagedSessionsForFgs.getOrDefault(uid, Set.of())) {
- ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
- mediaSessionRecord.getForegroundServiceDelegationOptions();
- if (foregroundServiceDelegationOptions != null
- && mediaSessionRecord.isLinkedToNotification(postedNotification)) {
- startFgsDelegate(foregroundServiceDelegationOptions);
+ if (mediaSessionRecord.isLinkedToNotification(postedNotification)) {
+ startFgsDelegateLocked(mediaSessionRecord);
return;
}
}