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

Commit fc0658ab authored by Tanay Khemani's avatar Tanay Khemani Committed by Android (Google) Code Review
Browse files

Merge changes from topic "enum_update_and_log" into main

* changes:
  Log media routing change info to WW
  Use android.util.LruCache instead of a custom definition
parents 115083e3 8b6a56b3
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -38,13 +38,6 @@ public final class RoutingChangeInfo implements Parcelable {
    // Indicates that the route was a suggested route.
    private final boolean mIsSuggested;

    /**
     * Unspecified default value.
     *
     * @hide
     */
    public static final int ENTRY_POINT_UNSPECIFIED = 0;

    /**
     * Indicates that a routing session started as the result of selecting a route from the output
     * switcher.
@@ -95,7 +88,6 @@ public final class RoutingChangeInfo implements Parcelable {
    @IntDef(
            prefix = "ENTRY_POINT",
            value = {
                ENTRY_POINT_UNSPECIFIED,
                ENTRY_POINT_SYSTEM_OUTPUT_SWITCHER,
                ENTRY_POINT_SYSTEM_MEDIA_CONTROLS,
                ENTRY_POINT_LOCAL_ROUTER_UNSPECIFIED,
+8 −2
Original line number Diff line number Diff line
@@ -1569,6 +1569,7 @@ class MediaRouter2ServiceImpl {
        mMediaRouterMetricLogger.addRequestInfo(
                uniqueRequestId,
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
        mMediaRouterMetricLogger.notifyRoutingChangeRequested(uniqueRequestId, routingChangeInfo);
        userHandler.sendMessage(
                obtainMessage(
                        UserHandler::requestCreateSessionWithRouter2OnHandler,
@@ -3627,10 +3628,13 @@ class MediaRouter2ServiceImpl {
            }

            provider.releaseSession(uniqueRequestId, sessionId);
            mMediaRouterMetricLogger.notifySessionEnd(sessionId);
        }

        private void onSessionCreatedOnHandler(@NonNull MediaRoute2Provider provider,
                long uniqueRequestId, @NonNull RoutingSessionInfo sessionInfo) {
        private void onSessionCreatedOnHandler(
                @NonNull MediaRoute2Provider provider,
                long uniqueRequestId,
                @NonNull RoutingSessionInfo sessionInfo) {
            SessionCreationRequest matchingRequest = null;

            for (SessionCreationRequest request : mSessionCreationRequests) {
@@ -3687,6 +3691,8 @@ class MediaRouter2ServiceImpl {
            // Log the success result.
            mMediaRouterMetricLogger.logRequestResult(
                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
            mMediaRouterMetricLogger.notifyRoutingChange(
                    uniqueRequestId, sessionInfo, matchingRequest.mRouterRecord.mUid);
        }

        /**
+269 −61
Original line number Diff line number Diff line
@@ -16,6 +16,15 @@

package com.android.server.media;

import static android.media.RoutingChangeInfo.ENTRY_POINT_LOCAL_ROUTER_UNSPECIFIED;
import static android.media.RoutingChangeInfo.ENTRY_POINT_PROXY_ROUTER_UNSPECIFIED;
import static android.media.RoutingChangeInfo.ENTRY_POINT_SYSTEM_MEDIA_CONTROLS;
import static android.media.RoutingChangeInfo.ENTRY_POINT_SYSTEM_OUTPUT_SWITCHER;
import static android.media.RoutingChangeInfo.ENTRY_POINT_TV_OUTPUT_SWITCHER;
import static android.media.RoutingSessionInfo.TRANSFER_REASON_APP;
import static android.media.RoutingSessionInfo.TRANSFER_REASON_FALLBACK;
import static android.media.RoutingSessionInfo.TRANSFER_REASON_SYSTEM_REQUEST;

import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STARTED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STOPPED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
@@ -26,15 +35,31 @@ import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_RE
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_LOCAL_ROUTER;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_PROXY_ROUTER;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_SYSTEM_MEDIA_CONTROLS;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_SYSTEM_OUTPUT_SWITCHER;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_TV_OUTPUT_SWITCHER;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_APP;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_FALLBACK;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_SYSTEM_REQUEST;
import static com.android.server.media.MediaRouterStatsLog.ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_UNSPECIFIED;

import android.annotation.NonNull;
import android.media.MediaRoute2ProviderService;
import android.media.RoutingChangeInfo;
import android.media.RoutingChangeInfo.EntryPoint;
import android.media.RoutingSessionInfo;
import android.media.RoutingSessionInfo.TransferReason;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.util.LruCache;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Logs metrics for MediaRouter2.
@@ -47,11 +72,52 @@ final class MediaRouterMetricLogger {
    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;

    /** LRU cache to store request info. */
    private final RequestInfoCache mRequestInfoCache;
    private final EvictionCallbackLruCache<Long, RequestInfo> mRequestInfoCache;

    /** LRU cache to store information about the invocation of a routing change. */
    private final EvictionCallbackLruCache<Long, RoutingChangeInfo> mRoutingChangeInfoCache;

    /** LRU cache to store information for an ongoing routing change. */
    private final EvictionCallbackLruCache<String, OngoingRoutingChange> mOngoingRoutingChangeCache;

    /** Constructor for {@link MediaRouterMetricLogger}. */
    public MediaRouterMetricLogger() {
        mRequestInfoCache = new RequestInfoCache(REQUEST_INFO_CACHE_CAPACITY);
        mRequestInfoCache =
                new EvictionCallbackLruCache<>(
                        REQUEST_INFO_CACHE_CAPACITY, new OnRequestInfoEvictedListener());
        mRoutingChangeInfoCache =
                new EvictionCallbackLruCache<>(
                        REQUEST_INFO_CACHE_CAPACITY, new OnRoutingChangeInfoEvictedListener());
        mOngoingRoutingChangeCache =
                new EvictionCallbackLruCache<>(
                        REQUEST_INFO_CACHE_CAPACITY, new OnOngoingRoutingChangeEvictedListener());
    }

    /**
     * Converts a reason code from {@link MediaRoute2ProviderService} to a result code for logging.
     *
     * @param reason The reason code from {@link MediaRoute2ProviderService}.
     * @return The result code for logging.
     */
    public static int convertResultFromReason(int reason) {
        switch (reason) {
            case MediaRoute2ProviderService.REASON_UNKNOWN_ERROR:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
            case MediaRoute2ProviderService.REASON_REJECTED:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
            case MediaRoute2ProviderService.REASON_NETWORK_ERROR:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
            case MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
            case MediaRoute2ProviderService.REASON_INVALID_COMMAND:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
            case MediaRoute2ProviderService.REASON_UNIMPLEMENTED:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
            case MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
            default:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
        }
    }

    /**
@@ -128,45 +194,139 @@ final class MediaRouterMetricLogger {
        }
    }

    /** Logs the scanning started event. */
    private void logScanningStarted() {
        logMediaRouterEvent(
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STARTED,
                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
    /**
     * Stores {@link RoutingChangeInfo} when a routing change is requested. This is appended with
     * routing session information when {@link MediaRouterMetricLogger#notifyRoutingChange(long,
     * RoutingSessionInfo, int)} is called.
     *
     * @param uniqueRequestId the unique request id for a routing change.
     * @param routingChangeInfo the routing change request information.
     */
    public void notifyRoutingChangeRequested(
            long uniqueRequestId, RoutingChangeInfo routingChangeInfo) {
        mRoutingChangeInfoCache.put(uniqueRequestId, routingChangeInfo);
    }

    /** Logs the scanning stopped event. */
    private void logScanningStopped() {
        logMediaRouterEvent(
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STOPPED,
                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
    /**
     * Stores an {@link OngoingRoutingChange} when a routing change occurs. This is logged when
     * {@link MediaRouterMetricLogger#notifySessionEnd(String)} is called with the corresponding
     * sessionId.
     *
     * @param uniqueRequestId the unique request id corresponding to the routing change request.
     *     This should be same as the one passed into {@link
     *     MediaRouterMetricLogger#notifyRoutingChangeRequested(long, RoutingChangeInfo)}
     * @param routingSessionInfo information of the media routing session.
     * @param clientPackageUid uid of the client package for which the routing is taking place.
     */
    public void notifyRoutingChange(
            long uniqueRequestId, RoutingSessionInfo routingSessionInfo, int clientPackageUid) {
        RoutingChangeInfo routingChangeInfo = mRoutingChangeInfoCache.get(uniqueRequestId);
        if (routingChangeInfo == null) {
            Slog.e(TAG, "Unable to get routing change info for the specified request id.");
            return;
        }
        OngoingRoutingChange ongoingRoutingChange =
                new OngoingRoutingChange(
                        routingChangeInfo.getEntryPoint(),
                        clientPackageUid,
                        routingSessionInfo.isSystemSession(),
                        routingSessionInfo.getTransferReason(),
                        routingChangeInfo.isSuggested(),
                        SystemClock.elapsedRealtime());
        mOngoingRoutingChangeCache.put(routingSessionInfo.getOriginalId(), ongoingRoutingChange);
        mRoutingChangeInfoCache.remove(uniqueRequestId);
    }

    /**
     * Converts a reason code from {@link MediaRoute2ProviderService} to a result code for logging.
     * Logs the {@link OngoingRoutingChange} corresponding to the sessionId
     *
     * @param reason The reason code from {@link MediaRoute2ProviderService}.
     * @return The result code for logging.
     * @param sessionId id of the session which has ended
     */
    public static int convertResultFromReason(int reason) {
        switch (reason) {
            case MediaRoute2ProviderService.REASON_UNKNOWN_ERROR:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
            case MediaRoute2ProviderService.REASON_REJECTED:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
            case MediaRoute2ProviderService.REASON_NETWORK_ERROR:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
            case MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
            case MediaRoute2ProviderService.REASON_INVALID_COMMAND:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
            case MediaRoute2ProviderService.REASON_UNIMPLEMENTED:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
            case MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
            default:
                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
    public void notifySessionEnd(String sessionId) {
        OngoingRoutingChange ongoingRoutingChange = mOngoingRoutingChangeCache.get(sessionId);
        if (ongoingRoutingChange == null) {
            Slog.e(TAG, "Unable to get routing change logging info for the specified sessionId.");
            return;
        }
        long sessionLengthInMillis =
                SystemClock.elapsedRealtime() - ongoingRoutingChange.startTimeInMillis;

        if (DEBUG) {
            Slog.d(
                    TAG,
                    TextUtils.formatSimple(
                            "notifySessionEnd | EntryPoint: %d, ClientPackageUid: %d,"
                                    + " IsSystemSession: %b, TransferReason: %d, IsSuggested: %b,"
                                    + " SessionLengthInMillis: %d",
                            ongoingRoutingChange.entryPoint,
                            ongoingRoutingChange.clientPackageUid,
                            ongoingRoutingChange.isSystemSession,
                            ongoingRoutingChange.transferReason,
                            ongoingRoutingChange.isSuggested,
                            sessionLengthInMillis));
        }

        MediaRouterStatsLog.write(
                MediaRouterStatsLog.ROUTING_CHANGE_REPORTED,
                convertEntryPointForLogging(ongoingRoutingChange.entryPoint),
                ongoingRoutingChange.clientPackageUid,
                ongoingRoutingChange.isSystemSession,
                convertTransferReasonForLogging(ongoingRoutingChange.transferReason),
                ongoingRoutingChange.isSuggested,
                sessionLengthInMillis);

        mOngoingRoutingChangeCache.remove(sessionId);
    }

    /**
     * Converts {@link TransferReason} from {@link RoutingSessionInfo} to the transfer reason enum
     * defined for logging.
     *
     * @param transferReason the transfer reason as specified in {@link RoutingSessionInfo}
     * @return the transfer reason as per the enum defined for logging.
     */
    @VisibleForTesting
    /*package*/ static int convertTransferReasonForLogging(@TransferReason int transferReason) {
        return switch (transferReason) {
            case TRANSFER_REASON_FALLBACK ->
                    ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_FALLBACK;
            case TRANSFER_REASON_SYSTEM_REQUEST ->
                    ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_SYSTEM_REQUEST;
            case TRANSFER_REASON_APP ->
                    ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_APP;
            default -> ROUTING_CHANGE_REPORTED__TRANSFER_REASON__TRANSFER_REASON_UNSPECIFIED;
        };
    }

    /**
     * Converts {@link EntryPoint} from {@link RoutingChangeInfo} to the entry point enum defined
     * for logging.
     *
     * @param entryPoint the entry point as specified in {@link RoutingChangeInfo}
     * @return the entry point as per the enum defined for logging.
     */
    @VisibleForTesting
    /* package */ static int convertEntryPointForLogging(@EntryPoint int entryPoint) {
        return switch (entryPoint) {
            case ENTRY_POINT_SYSTEM_OUTPUT_SWITCHER ->
                    ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_SYSTEM_OUTPUT_SWITCHER;
            case ENTRY_POINT_SYSTEM_MEDIA_CONTROLS ->
                    ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_SYSTEM_MEDIA_CONTROLS;
            case ENTRY_POINT_LOCAL_ROUTER_UNSPECIFIED ->
                    ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_LOCAL_ROUTER;
            case ENTRY_POINT_PROXY_ROUTER_UNSPECIFIED ->
                    ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_PROXY_ROUTER;
            case ENTRY_POINT_TV_OUTPUT_SWITCHER ->
                    ROUTING_CHANGE_REPORTED__ENTRY_POINT__ENTRY_POINT_TV_OUTPUT_SWITCHER;
            default ->
                    throw new IllegalArgumentException(
                            "No mapping found for the given entry point: " + entryPoint);
        };
    }

    @VisibleForTesting
    /* package */ int getRequestInfoCacheCapacity() {
        return mRequestInfoCache.maxSize();
    }

    /**
@@ -175,7 +335,7 @@ final class MediaRouterMetricLogger {
     * @return The size of the request info cache.
     */
    @VisibleForTesting
    public int getRequestCacheSize() {
    /* package */ int getRequestCacheSize() {
        return mRequestInfoCache.size();
    }

@@ -188,33 +348,19 @@ final class MediaRouterMetricLogger {
        }
    }

    /** A cache for storing request info that evicts entries when it reaches its capacity. */
    class RequestInfoCache extends LinkedHashMap<Long, RequestInfo> {

        public final int capacity;

        /**
         * Constructor for {@link RequestInfoCache}.
         *
         * @param capacity The maximum capacity of the cache.
         */
        public RequestInfoCache(int capacity) {
            super(capacity, 1.0f, true);
            this.capacity = capacity;
    /** Logs the scanning started event. */
    private void logScanningStarted() {
        logMediaRouterEvent(
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STARTED,
                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
    }

        @Override
        protected boolean removeEldestEntry(Map.Entry<Long, RequestInfo> eldest) {
            boolean shouldRemove = size() > capacity;
            if (shouldRemove) {
                Slog.d(TAG, "Evicted request info: " + eldest.getValue());
                logOperationTriggered(
                        eldest.getValue().mEventType,
    /** Logs the scanning stopped event. */
    private void logScanningStopped() {
        logMediaRouterEvent(
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SCANNING_STOPPED,
                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
    }
            return shouldRemove;
        }
    }

    /** Class to store request info. */
    static class RequestInfo {
@@ -245,4 +391,66 @@ final class MediaRouterMetricLogger {
            pw.println(indent + "mEventType=" + mEventType);
        }
    }

    /**
     * A subclass of {@link LruCache} which takes in an {@link OnEntryEvictedListener} to be invoked
     * on eviction of an entry.
     */
    private static class EvictionCallbackLruCache<K, V> extends LruCache<K, V> {

        private final OnEntryEvictedListener<K, V> mOnEntryEvictedListener;

        EvictionCallbackLruCache(int maxSize, OnEntryEvictedListener<K, V> onEntryEvictedListener) {
            super(maxSize);
            mOnEntryEvictedListener = onEntryEvictedListener;
        }

        @Override
        protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {
            if (evicted) {
                mOnEntryEvictedListener.onEntryEvicted(key, oldValue);
            }
        }
    }

    private class OnRequestInfoEvictedListener
            implements OnEntryEvictedListener<Long, RequestInfo> {

        @Override
        public void onEntryEvicted(Long key, RequestInfo value) {
            Slog.d(TAG, "Evicted request info: " + value.mUniqueRequestId);
            logOperationTriggered(
                    value.mEventType, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
        }
    }

    private static class OnRoutingChangeInfoEvictedListener
            implements OnEntryEvictedListener<Long, RoutingChangeInfo> {

        @Override
        public void onEntryEvicted(Long key, RoutingChangeInfo value) {
            Slog.w(TAG, "Routing change info evicted from cache with requestId: " + key);
        }
    }

    private static class OnOngoingRoutingChangeEvictedListener
            implements OnEntryEvictedListener<String, OngoingRoutingChange> {
        @Override
        public void onEntryEvicted(String key, OngoingRoutingChange ongoingRoutingChange) {
            Slog.w(TAG, "Routing change info evicted from cache with sessionId: " + key);
        }
    }

    private interface OnEntryEvictedListener<K, V> {
        void onEntryEvicted(K key, V value);
    }

    /** Information about an ongoing routing change. */
    private record OngoingRoutingChange(
            @EntryPoint int entryPoint,
            int clientPackageUid,
            boolean isSystemSession,
            @TransferReason int transferReason,
            boolean isSuggested,
            long startTimeInMillis) {}
}
+31 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
import static android.media.MediaRoute2ProviderService.REASON_UNIMPLEMENTED;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
@@ -35,10 +36,13 @@ import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_RE
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;

import static com.google.common.truth.Truth.assertThat;

import androidx.test.runner.AndroidJUnit4;

import com.android.modules.utils.testing.ExtendedMockitoRule;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -137,4 +141,31 @@ public class MediaRouterMetricLoggerTest {
                123, MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
        assertThat(mLogger.getRequestCacheSize()).isEqualTo(1);
    }

    @Test
    public void addRequestInfo_whenCacheFull_evictsFromCacheAndLogsUnspecified() {
        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);

        // Fill the cache to capacity.
        int cacheCapacity = mLogger.getRequestInfoCacheCapacity();
        for (int i = 0; i < cacheCapacity; i++) {
            mLogger.addRequestInfo(
                    /* uniqueRequestId= */ i,
                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
        }

        // Add one more request to trigger eviction.
        mLogger.addRequestInfo(
                /* uniqueRequestId= */ cacheCapacity,
                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);

        // Verify cache size is correct and generic result gets logged.
        assertThat(mLogger.getRequestCacheSize()).isEqualTo(cacheCapacity);
        verify(
                () ->
                        MediaRouterStatsLog.write(
                                MEDIA_ROUTER_EVENT_REPORTED,
                                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
                                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED));
    }
}