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

Commit 0a9a673c authored by tanaykhemani's avatar tanaykhemani
Browse files

Log metric to track device suggestion usage

Bug: 440343393
Test: atest CtsMediaRouterTestCases
Flag: EXEMPT logging only change
Change-Id: I199eb57f16d4651c6aaa04bd8b66d3468ffc61b1
parent 7c5a466f
Loading
Loading
Loading
Loading
+34 −1
Original line number Original line Diff line number Diff line
@@ -76,6 +76,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.TextUtils;
@@ -703,6 +704,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPid,
                        callerPackageName,
                        callerPackageName,
                        /* targetPackageName */ null,
                        /* targetPackageName */ null,
                        /* targetUid= */ Process.INVALID_UID,
                        callerUser);
                        callerUser);
            }
            }
        } finally {
        } finally {
@@ -746,6 +748,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPid,
                        callerPackageName,
                        callerPackageName,
                        targetPackageName,
                        targetPackageName,
                        getUidForPackage(targetPackageName, targetUser),
                        targetUser);
                        targetUser);
            }
            }
        } finally {
        } finally {
@@ -1136,6 +1139,19 @@ class MediaRouter2ServiceImpl {
        }
        }
    }
    }


    @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS)
    private int getUidForPackage(@NonNull String clientPackageName, @NonNull UserHandle user) {
        try {
            PackageManager pm = mContext.getPackageManager();
            return pm.getApplicationInfoAsUser(
                            clientPackageName, /* flags= */ 0, user.getIdentifier())
                    .uid;

        } catch (PackageManager.NameNotFoundException ex) {
            return Process.INVALID_UID;
        }
    }

    /**
    /**
     * Enforces the caller has {@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} if the
     * Enforces the caller has {@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} if the
     * caller's user is different from the target user.
     * caller's user is different from the target user.
@@ -1828,6 +1844,9 @@ class MediaRouter2ServiceImpl {
                        routerRecord.mPackageName,
                        routerRecord.mPackageName,
                        routerRecord.mPackageName,
                        routerRecord.mPackageName,
                        suggestedDeviceInfo));
                        suggestedDeviceInfo));
        mMediaRouterMetricLogger.notifyDeviceSuggestionsUpdated(
                /* targetPackageUid= */ routerRecord.mUid,
                /* suggestingPackageUid= */ routerRecord.mUid);
    }
    }


    @GuardedBy("mLock")
    @GuardedBy("mLock")
@@ -1897,6 +1916,7 @@ class MediaRouter2ServiceImpl {
            int callerPid,
            int callerPid,
            @NonNull String callerPackageName,
            @NonNull String callerPackageName,
            @Nullable String targetPackageName,
            @Nullable String targetPackageName,
            int targetUid,
            @NonNull UserHandle targetUser) {
            @NonNull UserHandle targetUser) {
        final IBinder binder = manager.asBinder();
        final IBinder binder = manager.asBinder();
        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1935,6 +1955,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPid,
                        callerPackageName,
                        callerPackageName,
                        targetPackageName,
                        targetPackageName,
                        targetUid,
                        hasMediaRoutingControl,
                        hasMediaRoutingControl,
                        hasMediaContentControl);
                        hasMediaContentControl);
        try {
        try {
@@ -2307,6 +2328,8 @@ class MediaRouter2ServiceImpl {
                        managerRecord.mTargetPackageName,
                        managerRecord.mTargetPackageName,
                        managerRecord.mOwnerPackageName,
                        managerRecord.mOwnerPackageName,
                        suggestedDeviceInfo));
                        suggestedDeviceInfo));
        mMediaRouterMetricLogger.notifyDeviceSuggestionsUpdated(
                managerRecord.mTargetUid, managerRecord.mOwnerUid);
    }
    }


    @GuardedBy("mLock")
    @GuardedBy("mLock")
@@ -2368,6 +2391,8 @@ class MediaRouter2ServiceImpl {
                        UserHandler::notifyDeviceSuggestionRequestedOnHandler,
                        UserHandler::notifyDeviceSuggestionRequestedOnHandler,
                        managerRecord.mUserRecord.mHandler,
                        managerRecord.mUserRecord.mHandler,
                        managerRecord.mTargetPackageName));
                        managerRecord.mTargetPackageName));
        mMediaRouterMetricLogger.notifyDeviceSuggestionsRequested(
                managerRecord.mTargetUid, managerRecord.mOwnerUid);
    }
    }


    // End of locked methods that are used by MediaRouter2Manager.
    // End of locked methods that are used by MediaRouter2Manager.
@@ -2952,9 +2977,15 @@ class MediaRouter2ServiceImpl {
        public final int mOwnerPid;
        public final int mOwnerPid;
        @NonNull public final String mOwnerPackageName;
        @NonNull public final String mOwnerPackageName;
        public final int mManagerId;
        public final int mManagerId;
        // TODO (b/281072508): Document behaviour around nullability for mTargetPackageName.
        // The target package name can be null when the manager does not target a local router.
        @Nullable public final String mTargetPackageName;
        @Nullable public final String mTargetPackageName;


        /**
         * The target Uid can be {@link Process.INVALID_UID} if the manager does not target a local
         * router.
         */
        public final int mTargetUid;

        public final boolean mHasMediaRoutingControl;
        public final boolean mHasMediaRoutingControl;
        public final boolean mHasMediaContentControl;
        public final boolean mHasMediaContentControl;
        @Nullable public SessionCreationRequest mLastSessionCreationRequest;
        @Nullable public SessionCreationRequest mLastSessionCreationRequest;
@@ -2968,6 +2999,7 @@ class MediaRouter2ServiceImpl {
                int ownerPid,
                int ownerPid,
                @NonNull String ownerPackageName,
                @NonNull String ownerPackageName,
                @Nullable String targetPackageName,
                @Nullable String targetPackageName,
                int targetUid,
                boolean hasMediaRoutingControl,
                boolean hasMediaRoutingControl,
                boolean hasMediaContentControl) {
                boolean hasMediaContentControl) {
            mUserRecord = userRecord;
            mUserRecord = userRecord;
@@ -2976,6 +3008,7 @@ class MediaRouter2ServiceImpl {
            mOwnerPid = ownerPid;
            mOwnerPid = ownerPid;
            mOwnerPackageName = ownerPackageName;
            mOwnerPackageName = ownerPackageName;
            mTargetPackageName = targetPackageName;
            mTargetPackageName = targetPackageName;
            mTargetUid = targetUid;
            mManagerId = mNextRouterOrManagerId.getAndIncrement();
            mManagerId = mNextRouterOrManagerId.getAndIncrement();
            mHasMediaRoutingControl = hasMediaRoutingControl;
            mHasMediaRoutingControl = hasMediaRoutingControl;
            mHasMediaContentControl = hasMediaContentControl;
            mHasMediaContentControl = hasMediaContentControl;
+132 −6
Original line number Original line Diff line number Diff line
@@ -58,6 +58,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.media.MediaRoute2ProviderService;
import android.media.MediaRoute2ProviderService;
import android.media.MediaRouter2;
import android.media.RouteListingPreference;
import android.media.RouteListingPreference;
import android.media.RoutingChangeInfo;
import android.media.RoutingChangeInfo;
import android.media.RoutingChangeInfo.EntryPoint;
import android.media.RoutingChangeInfo.EntryPoint;
@@ -74,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;


/**
/**
 * Logs metrics for MediaRouter2.
 * Logs metrics for MediaRouter2.
@@ -112,6 +114,18 @@ final class MediaRouterMetricLogger {
    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;
    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;
    private static final int API_COUNT_CACHE_CAPACITY = 20;
    private static final int API_COUNT_CACHE_CAPACITY = 20;


    /** Corresponds to {@link MediaRouter2#setDeviceSuggestions calls } */
    private static final int SUGGESTION_INTERACTION_TYPE_UPDATE = 0;

    /** Corresponds to {@link MediaRouter2#notifyDeviceSuggestionRequested calls } */
    private static final int SUGGESTION_INTERACTION_TYPE_REQUEST = 1;

    @IntDef(
            prefix = "SUGGESTION_INTERACTION_TYPE",
            value = {SUGGESTION_INTERACTION_TYPE_UPDATE, SUGGESTION_INTERACTION_TYPE_REQUEST})
    @Retention(RetentionPolicy.SOURCE)
    private @interface SuggestionInteractionType {}

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


@@ -127,6 +141,13 @@ final class MediaRouterMetricLogger {
     */
     */
    private final EvictionCallbackLruCache<Integer, RlpCount> mRlpCountCache;
    private final EvictionCallbackLruCache<Integer, RlpCount> mRlpCountCache;


    /**
     * LRU cache to store counts of device suggestion calls for a target and suggesting package
     * pair.
     */
    private final EvictionCallbackLruCache<PackagePair, DeviceSuggestionsCount>
            mDeviceSuggestionsCountCache;

    /** Constructor for {@link MediaRouterMetricLogger}. */
    /** Constructor for {@link MediaRouterMetricLogger}. */
    public MediaRouterMetricLogger() {
    public MediaRouterMetricLogger() {
        mRequestInfoCache =
        mRequestInfoCache =
@@ -141,6 +162,9 @@ final class MediaRouterMetricLogger {
        mRlpCountCache =
        mRlpCountCache =
                new EvictionCallbackLruCache<>(
                new EvictionCallbackLruCache<>(
                        API_COUNT_CACHE_CAPACITY, new OnRlpSuggestionCountEvictedListener());
                        API_COUNT_CACHE_CAPACITY, new OnRlpSuggestionCountEvictedListener());
        mDeviceSuggestionsCountCache =
                new EvictionCallbackLruCache<>(
                        API_COUNT_CACHE_CAPACITY, new OnDeviceSuggestionsCountEvictedListener());
    }
    }


    /**
    /**
@@ -361,6 +385,57 @@ final class MediaRouterMetricLogger {
                new RlpCount(rlpTotalCount + 1, rlpWithSuggestedCount + suggestedCountIncrement));
                new RlpCount(rlpTotalCount + 1, rlpWithSuggestedCount + suggestedCountIncrement));
    }
    }


    /**
     * Increments the count of device suggestion update calls for the target and suggesting package
     * pair.
     *
     * @param targetPackageUid Uid of the package for which devices are suggested.
     * @param suggestingPackageUid Uid of the package suggesting the devices.
     */
    public void notifyDeviceSuggestionsUpdated(int targetPackageUid, int suggestingPackageUid) {
        notifyDeviceSuggestionInteracted(
                targetPackageUid, suggestingPackageUid, SUGGESTION_INTERACTION_TYPE_UPDATE);
    }

    /**
     * Increments the count of device suggestion request calls for the target and suggesting package
     * pair.
     *
     * @param targetPackageUid Uid of the package for which devices are suggested.
     * @param suggestingPackageUid Uid of the package suggesting the devices.
     */
    public void notifyDeviceSuggestionsRequested(int targetPackageUid, int suggestingPackageUid) {
        notifyDeviceSuggestionInteracted(
                targetPackageUid, suggestingPackageUid, SUGGESTION_INTERACTION_TYPE_REQUEST);
    }

    private void notifyDeviceSuggestionInteracted(
            int targetPackageUid,
            int suggestingPackageUid,
            @SuggestionInteractionType int suggestionInteractionType) {
        PackagePair packagePair = new PackagePair(targetPackageUid, suggestingPackageUid);
        DeviceSuggestionsCount deviceSuggestionsCount =
                mDeviceSuggestionsCountCache.get(packagePair);
        long updateSuggestionsCount = 0;
        long requestSuggestionsCount = 0;
        if (deviceSuggestionsCount != null) {
            updateSuggestionsCount = deviceSuggestionsCount.updateSuggestionsCount;
            requestSuggestionsCount = deviceSuggestionsCount.requestSuggestionsCount;
        }

        switch (suggestionInteractionType) {
            case SUGGESTION_INTERACTION_TYPE_UPDATE:
                updateSuggestionsCount++;
                break;
            case SUGGESTION_INTERACTION_TYPE_REQUEST:
                requestSuggestionsCount++;
                break;
        }
        mDeviceSuggestionsCountCache.put(
                packagePair,
                new DeviceSuggestionsCount(updateSuggestionsCount, requestSuggestionsCount));
    }

    /**
    /**
     * This is called when a {@link android.media.MediaRouter2} instance is unregistered. It takes
     * This is called when a {@link android.media.MediaRouter2} instance is unregistered. It takes
     * care of logging metrics aggregated over the lifecycle of the {@link
     * care of logging metrics aggregated over the lifecycle of the {@link
@@ -370,12 +445,8 @@ final class MediaRouterMetricLogger {
     *     android.media.MediaRouter2} instance.
     *     android.media.MediaRouter2} instance.
     */
     */
    public void notifyRouterUnregistered(int routerPackageUid) {
    public void notifyRouterUnregistered(int routerPackageUid) {
        RlpCount rlpCount = mRlpCountCache.remove(routerPackageUid);
        logRlpCountForRouter(routerPackageUid);
        if (rlpCount == null) {
        logDeviceSuggestionsCountForRouter(routerPackageUid);
            // This helps track scenarios where MediaRouter2 is used but not RLP.
            rlpCount = new RlpCount(0, 0);
        }
        logRlpCountForRouter(routerPackageUid, rlpCount);
    }
    }


    /**
    /**
@@ -522,6 +593,15 @@ final class MediaRouterMetricLogger {
                /* routingChangeInfo= */ null);
                /* routingChangeInfo= */ null);
    }
    }


    private void logRlpCountForRouter(int routerPackageUid) {
        RlpCount rlpCount = mRlpCountCache.remove(routerPackageUid);
        if (rlpCount == null) {
            // This helps track scenarios where MediaRouter2 is used but not RLP.
            rlpCount = new RlpCount(0, 0);
        }
        logRlpCountForRouter(routerPackageUid, rlpCount);
    }

    private void logRlpCountForRouter(int routerPackageId, RlpCount rlpCount) {
    private void logRlpCountForRouter(int routerPackageId, RlpCount rlpCount) {
        MediaRouterStatsLog.write(
        MediaRouterStatsLog.write(
                MediaRouterStatsLog.ROUTE_LISTING_PREFERENCE_UPDATED,
                MediaRouterStatsLog.ROUTE_LISTING_PREFERENCE_UPDATED,
@@ -530,6 +610,25 @@ final class MediaRouterMetricLogger {
                rlpCount.rlpWithSuggestionCount);
                rlpCount.rlpWithSuggestionCount);
    }
    }


    private void logDeviceSuggestionsCountForRouter(int routerPackageUid) {
        for (Map.Entry<PackagePair, DeviceSuggestionsCount> entry :
                mDeviceSuggestionsCountCache.snapshot().entrySet()) {
            if (entry.getKey().targetPackageUid == routerPackageUid) {
                logDeviceSuggestionsAccessed(entry.getKey(), entry.getValue());
            }
        }
    }

    private void logDeviceSuggestionsAccessed(
            PackagePair packagePair, DeviceSuggestionsCount deviceSuggestionsCount) {
        MediaRouterStatsLog.write(
                MediaRouterStatsLog.DEVICE_SUGGESTIONS_INTERACTION_REPORTED,
                packagePair.targetPackageUid,
                packagePair.operatingPackageUid,
                deviceSuggestionsCount.updateSuggestionsCount,
                deviceSuggestionsCount.requestSuggestionsCount);
    }

    /** Class to store request info. */
    /** Class to store request info. */
    static class RequestInfo {
    static class RequestInfo {
        public final long mUniqueRequestId;
        public final long mUniqueRequestId;
@@ -626,6 +725,15 @@ final class MediaRouterMetricLogger {
        }
        }
    }
    }


    private class OnDeviceSuggestionsCountEvictedListener
            implements OnEntryEvictedListener<PackagePair, DeviceSuggestionsCount> {
        @Override
        public void onEntryEvicted(PackagePair key, DeviceSuggestionsCount value) {
            Slog.w(TAG, "Device suggestions count evicted from cache");
            logDeviceSuggestionsAccessed(key, value);
        }
    }

    private interface OnEntryEvictedListener<K, V> {
    private interface OnEntryEvictedListener<K, V> {
        void onEntryEvicted(K key, V value);
        void onEntryEvicted(K key, V value);
    }
    }
@@ -641,4 +749,22 @@ final class MediaRouterMetricLogger {


    /** Tracks the count of changes in route listing preference */
    /** Tracks the count of changes in route listing preference */
    private record RlpCount(long rlpTotalCount, long rlpWithSuggestionCount) {}
    private record RlpCount(long rlpTotalCount, long rlpWithSuggestionCount) {}

    /** Tracks the count of device suggestion interaction. */
    private record DeviceSuggestionsCount(
            // Count of the number of calls made to update device suggestions.
            long updateSuggestionsCount,
            // Count of the number of calls made to request device suggestions.
            long requestSuggestionsCount) {}

    /**
     * Holds a pair of uids of the target package and the operating package. For example, for device
     * suggestions the target package would be the package for which suggestions are being made and
     * the operating package would be the package making the suggestions.
     */
    private record PackagePair(
            // The uid of the package on which the operations are being performed.
            int targetPackageUid,
            // The uid of the operating package.
            int operatingPackageUid) {}
}
}