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

Commit 658a8346 authored by Santiago Seifert's avatar Santiago Seifert Committed by Android (Google) Code Review
Browse files

Merge "Implement system session lifecycle callbacks" into main

parents a2949136 73c6cb34
Loading
Loading
Loading
Loading
+53 −13
Original line number Diff line number Diff line
@@ -226,6 +226,10 @@ public abstract class MediaRoute2ProviderService extends Service {
    @GuardedBy("mSessionLock")
    private final ArrayMap<String, MediaStreams> mOngoingMediaStreams = new ArrayMap<>();

    @GuardedBy("mSessionLock")
    private final ArrayMap<String, RoutingSessionInfo> mPendingSystemSessionReleases =
            new ArrayMap<>();

    public MediaRoute2ProviderService() {
        mHandler = new Handler(Looper.getMainLooper());
    }
@@ -419,7 +423,7 @@ public abstract class MediaRoute2ProviderService extends Service {
        }

        AudioFormat audioFormat = formats.mAudioFormat;
        var mediaStreamsBuilder = new MediaStreams.Builder();
        var mediaStreamsBuilder = new MediaStreams.Builder(sessionInfo);
        if (audioFormat != null) {
            populateAudioStream(audioFormat, uid, mediaStreamsBuilder);
        }
@@ -526,8 +530,14 @@ public abstract class MediaRoute2ProviderService extends Service {
        RoutingSessionInfo sessionInfo;
        synchronized (mSessionLock) {
            sessionInfo = mSessionInfos.remove(sessionId);
            maybeReleaseMediaStreams(sessionId);

            if (Flags.enableMirroringInMediaRouter2()) {
                if (sessionInfo == null) {
                    sessionInfo = maybeReleaseMediaStreams(sessionId);
                }
                if (sessionInfo == null) {
                    sessionInfo = mPendingSystemSessionReleases.remove(sessionId);
                }
            }
            if (sessionInfo == null) {
                Log.w(TAG, "notifySessionReleased: Ignoring unknown session info.");
                return;
@@ -544,20 +554,26 @@ public abstract class MediaRoute2ProviderService extends Service {
        }
    }

    /** Releases any system media routing resources associated with the given {@code sessionId}. */
    private boolean maybeReleaseMediaStreams(String sessionId) {
    /**
     * Releases any system media routing resources associated with the given {@code sessionId}.
     *
     * @return The {@link RoutingSessionInfo} that corresponds to the released media streams, or
     *     null if no streams were released.
     */
    @Nullable
    private RoutingSessionInfo maybeReleaseMediaStreams(String sessionId) {
        if (!Flags.enableMirroringInMediaRouter2()) {
            return false;
            return null;
        }
        synchronized (mSessionLock) {
            var streams = mOngoingMediaStreams.remove(sessionId);
            if (streams != null) {
                releaseAudioStream(streams.mAudioPolicy, streams.mAudioRecord);
                // TODO: b/380431086: Release the video stream once implemented.
                return true;
                return streams.mSessionInfo;
            }
        }
        return false;
        return null;
    }

    // We cannot reach the code that requires MODIFY_AUDIO_ROUTING without holding it.
@@ -1026,12 +1042,16 @@ public abstract class MediaRoute2ProviderService extends Service {
            if (!checkCallerIsSystem()) {
                return;
            }
            // We proactively release the system media routing once the system requests it, to
            // ensure it happens immediately.
            if (!maybeReleaseMediaStreams(sessionId)
                    && !checkSessionIdIsValid(sessionId, "releaseSession")) {
            synchronized (mSessionLock) {
                // We proactively release the system media routing session resources when the
                // system requests it, to ensure it happens immediately.
                RoutingSessionInfo releasedSession = maybeReleaseMediaStreams(sessionId);
                if (releasedSession != null) {
                    mPendingSystemSessionReleases.put(sessionId, releasedSession);
                } else if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
                    return;
                }
            }

            addRequestId(requestId);
            mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
@@ -1054,9 +1074,19 @@ public abstract class MediaRoute2ProviderService extends Service {
        @Nullable private final AudioPolicy mAudioPolicy;
        @Nullable private final AudioRecord mAudioRecord;

        /**
         * Holds the last {@link RoutingSessionInfo} associated with these streams.
         *
         * @hide
         */
        @GuardedBy("MediaRoute2ProviderService.this.mSessionLock")
        @NonNull
        private RoutingSessionInfo mSessionInfo;

        // TODO: b/380431086: Add the video equivalent.

        private MediaStreams(Builder builder) {
            this.mSessionInfo = builder.mSessionInfo;
            this.mAudioPolicy = builder.mAudioPolicy;
            this.mAudioRecord = builder.mAudioRecord;
        }
@@ -1077,9 +1107,19 @@ public abstract class MediaRoute2ProviderService extends Service {
         */
        public static final class Builder {

            @NonNull private RoutingSessionInfo mSessionInfo;
            @Nullable private AudioPolicy mAudioPolicy;
            @Nullable private AudioRecord mAudioRecord;

            /**
             * Constructor.
             *
             * @param sessionInfo The {@link RoutingSessionInfo} associated with these streams.
             */
            Builder(@NonNull RoutingSessionInfo sessionInfo) {
                mSessionInfo = requireNonNull(sessionInfo);
            }

            /** Populates system media audio-related structures. */
            public Builder setAudioStream(
                    @NonNull AudioPolicy audioPolicy, @NonNull AudioRecord audioRecord) {
+23 −2
Original line number Diff line number Diff line
@@ -179,8 +179,29 @@ abstract class MediaRoute2Provider {
        void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
        void onSessionCreated(@NonNull MediaRoute2Provider provider,
                long requestId, @Nullable RoutingSessionInfo sessionInfo);
        void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo);

        /**
         * Called when there's a session info change.
         *
         * <p>If the provided {@code sessionInfo} has a null {@link
         * RoutingSessionInfo#getClientPackageName()}, that means that it's applicable to all
         * packages. We call this type of routing session "global". This is typically used for
         * system provided {@link RoutingSessionInfo}. However, some applications may be exempted
         * from the global routing sessions, because their media is being routed using a session
         * different from the global routing session.
         *
         * @param provider The provider that owns the session that changed.
         * @param sessionInfo The new {@link RoutingSessionInfo}.
         * @param packageNamesWithRoutingSessionOverrides The names of packages that are not
         *     affected by global session changes. This set may only be non-empty when the {@code
         *     sessionInfo} is for the global session, and therefore has no {@link
         *     RoutingSessionInfo#getClientPackageName()}.
         */
        void onSessionUpdated(
                @NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo,
                Set<String> packageNamesWithRoutingSessionOverrides);

        void onSessionReleased(@NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo);

+20 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.media;

import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
import static android.media.MediaRoute2ProviderService.REQUEST_ID_NONE;

import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -499,6 +500,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
        synchronized (mLock) {
            var systemMediaSessionCallback = mRequestIdToSystemSessionRequest.get(requestId);
            if (systemMediaSessionCallback != null) {
                mRequestIdToSystemSessionRequest.remove(requestId);
                mSystemSessionCallbacks.put(newSession.getOriginalId(), systemMediaSessionCallback);
                systemMediaSessionCallback.onSessionUpdate(newSession);
                return;
@@ -674,7 +676,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {

    private void dispatchSessionUpdated(RoutingSessionInfo session) {
        mHandler.sendMessage(
                obtainMessage(mCallback::onSessionUpdated, this, session));
                obtainMessage(
                        mCallback::onSessionUpdated,
                        this,
                        session,
                        /* packageNamesWithRoutingSessionOverrides= */ Set.of()));
    }

    private void dispatchSessionReleased(RoutingSessionInfo session) {
@@ -717,6 +723,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider {
                for (RoutingSessionInfo sessionInfo : mSessionInfos) {
                    mCallback.onSessionReleased(this, sessionInfo);
                }
                if (Flags.enableMirroringInMediaRouter2()) {
                    for (var callback : mSystemSessionCallbacks.values()) {
                        callback.onSessionReleased();
                    }
                    mSystemSessionCallbacks.clear();
                    int requestsSize = mRequestIdToSystemSessionRequest.size();
                    for (int i = 0; i < requestsSize; i++) {
                        var callback = mRequestIdToSystemSessionRequest.valueAt(i);
                        var requestId = mRequestIdToSystemSessionRequest.keyAt(i);
                        callback.onRequestFailed(requestId, REASON_REJECTED);
                    }
                    mSystemSessionCallbacks.clear();
                }
                mSessionInfos.clear();
                mReleasingSessions.clear();
                mRequestIdToSessionCreationRequest.clear();
+34 −6
Original line number Diff line number Diff line
@@ -2634,10 +2634,17 @@ class MediaRouter2ServiceImpl {
        }

        @Override
        public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo) {
            sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionInfoChangedOnHandler,
                    this, provider, sessionInfo));
        public void onSessionUpdated(
                @NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo,
                Set<String> packageNamesWithRoutingSessionOverrides) {
            sendMessage(
                    PooledLambda.obtainMessage(
                            UserHandler::onSessionInfoChangedOnHandler,
                            this,
                            provider,
                            sessionInfo,
                            packageNamesWithRoutingSessionOverrides));
        }

        @Override
@@ -3148,10 +3155,31 @@ class MediaRouter2ServiceImpl {
                    toOriginalRequestId(uniqueRequestId), sessionInfo);
        }

        private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo) {
        /**
         * Implementation of {@link MediaRoute2Provider.Callback#onSessionUpdated}.
         *
         * <p>Must run on the thread that corresponds to this {@link UserHandler}.
         */
        private void onSessionInfoChangedOnHandler(
                @NonNull MediaRoute2Provider provider,
                @NonNull RoutingSessionInfo sessionInfo,
                Set<String> packageNamesWithRoutingSessionOverrides) {
            List<ManagerRecord> managers = getManagerRecords();
            for (ManagerRecord manager : managers) {
                if (Flags.enableMirroringInMediaRouter2()) {
                    String targetPackageName = manager.mTargetPackageName;
                    boolean skipDueToOverride =
                            targetPackageName != null
                                    && packageNamesWithRoutingSessionOverrides.contains(
                                            targetPackageName);
                    boolean sessionIsForTargetPackage =
                            TextUtils.isEmpty(sessionInfo.getClientPackageName()) // is global.
                                    || TextUtils.equals(
                                            targetPackageName, sessionInfo.getClientPackageName());
                    if (skipDueToOverride || !sessionIsForTargetPackage) {
                        continue;
                    }
                }
                manager.notifySessionUpdated(sessionInfo);
            }

+8 −7
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    static final String SYSTEM_SESSION_ID = "SYSTEM_SESSION";

    private final AudioManager mAudioManager;
    private final Handler mHandler;
    protected final Handler mHandler;
    private final Context mContext;
    private final UserHandle mUser;

@@ -116,7 +116,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                        () -> {
                            publishProviderState();
                            if (updateSessionInfosIfNeeded()) {
                                notifySessionInfoUpdated();
                                notifyGlobalSessionInfoUpdated();
                            }
                        });

@@ -129,7 +129,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
                                        () -> {
                                            publishProviderState();
                                            if (updateSessionInfosIfNeeded()) {
                                                notifySessionInfoUpdated();
                                                notifyGlobalSessionInfoUpdated();
                                            }
                                        }));
    }
@@ -161,7 +161,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    public void setCallback(Callback callback) {
        super.setCallback(callback);
        notifyProviderState();
        notifySessionInfoUpdated();
        notifyGlobalSessionInfoUpdated();
    }

    @Override
@@ -296,7 +296,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {

        if (Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()
                && updateSessionInfosIfNeeded()) {
            notifySessionInfoUpdated();
            notifyGlobalSessionInfoUpdated();
        }
    }

@@ -643,7 +643,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
        notifyProviderState();
    }

    void notifySessionInfoUpdated() {
    void notifyGlobalSessionInfoUpdated() {
        if (mCallback == null) {
            return;
        }
@@ -656,7 +656,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
            sessionInfo = mSessionInfos.get(0);
        }

        mCallback.onSessionUpdated(this, sessionInfo);
        mCallback.onSessionUpdated(
                this, sessionInfo, /* packageNamesWithRoutingSessionOverrides= */ Set.of());
    }

    @Override
Loading