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

Commit 3987cfe4 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topics "ds_api_metric", "suggestionMap_shift" into main

* changes:
  Log metric to track device suggestion usage
  Move device suggestions map to RouterRecord from UserRecord
parents b7794121 0a9a673c
Loading
Loading
Loading
Loading
+102 −36
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -703,6 +704,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPackageName,
                        /* targetPackageName */ null,
                        /* targetUid= */ Process.INVALID_UID,
                        callerUser);
            }
        } finally {
@@ -746,6 +748,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPackageName,
                        targetPackageName,
                        getUidForPackage(targetPackageName, targetUser),
                        targetUser);
            }
        } 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
     * caller's user is different from the target user.
@@ -1398,6 +1414,13 @@ class MediaRouter2ServiceImpl {
        userRecord.mHandler.sendMessage(
                obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
                        userRecord.mHandler));
        routerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(
                        UserHandler::notifyDeviceSuggestionsClearedOnHandler,
                        routerRecord.mUserRecord.mHandler,
                        routerRecord.mPackageName,
                        routerRecord.getDeviceSuggestionsLocked().keySet()));
        routerRecord.mDeviceSuggestions.clear();
        mMediaRouterMetricLogger.notifyRouterUnregistered(routerRecord.mUid);
        routerRecord.dispose();
        disposeUserIfNeededLocked(userRecord); // since router removed from user
@@ -1813,8 +1836,7 @@ class MediaRouter2ServiceImpl {
                        "setDeviceSuggestions | router: %d suggestion: %d",
                        routerRecord.mPackageName, suggestedDeviceInfo));

        routerRecord.mUserRecord.updateDeviceSuggestionsLocked(
                routerRecord.mPackageName, routerRecord.mPackageName, suggestedDeviceInfo);
        routerRecord.putDeviceSuggestionsLocked(routerRecord.mPackageName, suggestedDeviceInfo);
        routerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(
                        UserHandler::notifyDeviceSuggestionsUpdatedOnHandler,
@@ -1822,6 +1844,9 @@ class MediaRouter2ServiceImpl {
                        routerRecord.mPackageName,
                        routerRecord.mPackageName,
                        suggestedDeviceInfo));
        mMediaRouterMetricLogger.notifyDeviceSuggestionsUpdated(
                /* targetPackageUid= */ routerRecord.mUid,
                /* suggestingPackageUid= */ routerRecord.mUid);
    }

    @GuardedBy("mLock")
@@ -1836,7 +1861,7 @@ class MediaRouter2ServiceImpl {
                    TAG,
                    TextUtils.formatSimple(
                            "Attempted to get device suggestion for unknown router: %s", router));
            return null;
            return Collections.emptyMap();
        }

        Slog.i(
@@ -1844,7 +1869,7 @@ class MediaRouter2ServiceImpl {
                TextUtils.formatSimple(
                        "getDeviceSuggestions | router: %d", routerRecord.mPackageName));

        return routerRecord.mUserRecord.getDeviceSuggestionsLocked(routerRecord.mPackageName);
        return routerRecord.getDeviceSuggestionsLocked();
    }

    // End of locked methods that are used by MediaRouter2.
@@ -1891,6 +1916,7 @@ class MediaRouter2ServiceImpl {
            int callerPid,
            @NonNull String callerPackageName,
            @Nullable String targetPackageName,
            int targetUid,
            @NonNull UserHandle targetUser) {
        final IBinder binder = manager.asBinder();
        ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1929,6 +1955,7 @@ class MediaRouter2ServiceImpl {
                        callerPid,
                        callerPackageName,
                        targetPackageName,
                        targetUid,
                        hasMediaRoutingControl,
                        hasMediaContentControl);
        try {
@@ -2281,10 +2308,19 @@ class MediaRouter2ServiceImpl {
                        managerRecord.mOwnerPackageName,
                        suggestedDeviceInfo));

        managerRecord.mUserRecord.updateDeviceSuggestionsLocked(
                managerRecord.mTargetPackageName,
                managerRecord.mOwnerPackageName,
                suggestedDeviceInfo);
        RouterRecord routerRecord =
                managerRecord.mUserRecord.findRouterRecordLocked(managerRecord.mTargetPackageName);
        if (routerRecord == null) {
            Slog.w(
                    TAG,
                    TextUtils.formatSimple(
                            "Router record not found for the target package: %s",
                            managerRecord.mTargetPackageName));
            return;
        }

        routerRecord.putDeviceSuggestionsLocked(
                managerRecord.mOwnerPackageName, suggestedDeviceInfo);
        managerRecord.mUserRecord.mHandler.sendMessage(
                obtainMessage(
                        UserHandler::notifyDeviceSuggestionsUpdatedOnHandler,
@@ -2292,6 +2328,8 @@ class MediaRouter2ServiceImpl {
                        managerRecord.mTargetPackageName,
                        managerRecord.mOwnerPackageName,
                        suggestedDeviceInfo));
        mMediaRouterMetricLogger.notifyDeviceSuggestionsUpdated(
                managerRecord.mTargetUid, managerRecord.mOwnerUid);
    }

    @GuardedBy("mLock")
@@ -2306,7 +2344,7 @@ class MediaRouter2ServiceImpl {
                    TAG,
                    TextUtils.formatSimple(
                            "Attempted to get device suggestion for unknown manager: %s", manager));
            return null;
            return Collections.emptyMap();
        }

        Slog.i(
@@ -2315,8 +2353,17 @@ class MediaRouter2ServiceImpl {
                        "getDeviceSuggestionsWithManagerLocked | manager: %d",
                        managerRecord.mManagerId));

        return managerRecord.mUserRecord.getDeviceSuggestionsLocked(
                managerRecord.mTargetPackageName);
        RouterRecord routerRecord =
                managerRecord.mUserRecord.findRouterRecordLocked(managerRecord.mTargetPackageName);
        if (routerRecord == null) {
            Slog.w(
                    TAG,
                    TextUtils.formatSimple(
                            "Router record not found for the target package: %s",
                            managerRecord.mTargetPackageName));
            return Collections.emptyMap();
        }
        return routerRecord.getDeviceSuggestionsLocked();
    }

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

    // End of locked methods that are used by MediaRouter2Manager.
@@ -2430,10 +2479,6 @@ class MediaRouter2ServiceImpl {
        // @GuardedBy("mLock")
        private final Set<String> mLastPackagesWithSystemOverridesLocked = new ArraySet<>();

        // @GuardedBy("mLock")
        private final Map<String, Map<String, List<SuggestedDeviceInfo>>> mDeviceSuggestions =
                new HashMap<>();

        RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
        Map<String, RouteDiscoveryPreference> mPerAppPreferences = Map.of();
        Set<String> mActivelyScanningPackages = Set.of();
@@ -2494,26 +2539,6 @@ class MediaRouter2ServiceImpl {
            return packageNames.stream().map(it -> new AppId(it, mUserHandle)).toList();
        }

        // @GuardedBy("mLock")
        public void updateDeviceSuggestionsLocked(
                String packageName,
                String suggestingPackageName,
                List<SuggestedDeviceInfo> deviceSuggestions) {
            mDeviceSuggestions.putIfAbsent(
                    packageName, new HashMap<String, List<SuggestedDeviceInfo>>());
            Map<String, List<SuggestedDeviceInfo>> suggestions =
                    mDeviceSuggestions.get(packageName);
            suggestions.put(suggestingPackageName, deviceSuggestions);
        }

        // @GuardedBy("mLock")
        @NonNull
        public Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestionsLocked(
                String packageName) {
            return mDeviceSuggestions.getOrDefault(
                    packageName, new HashMap<String, List<SuggestedDeviceInfo>>());
        }

        public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
            pw.println(prefix + "UserRecord");

@@ -2570,6 +2595,8 @@ class MediaRouter2ServiceImpl {

        public RouteDiscoveryPreference mDiscoveryPreference;
        @Nullable public RouteListingPreference mRouteListingPreference;
        // @GuardedBy("mLock")
        private final Map<String, List<SuggestedDeviceInfo>> mDeviceSuggestions = new HashMap<>();

        RouterRecord(
                Context context,
@@ -2814,6 +2841,29 @@ class MediaRouter2ServiceImpl {
            }
        }

        /**
         * Updates the device suggestions for the given suggesting package.
         *
         * @param suggestingPackageName The package name of the suggesting app.
         * @param deviceSuggestions The device suggestions.
         */
        @GuardedBy("mLock")
        public void putDeviceSuggestionsLocked(
                String suggestingPackageName, List<SuggestedDeviceInfo> deviceSuggestions) {
            mDeviceSuggestions.put(suggestingPackageName, deviceSuggestions);
        }

        /**
         * Returns the device suggestions for all suggesting packages.
         *
         * @return The device suggestions.
         */
        @NonNull
        @GuardedBy("mLock")
        public Map<String, List<SuggestedDeviceInfo>> getDeviceSuggestionsLocked() {
            return new HashMap<>(mDeviceSuggestions);
        }

        private RoutingSessionInfo maybeClearTransferInitiatorIdentity(
                @NonNull RoutingSessionInfo sessionInfo) {
            UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
@@ -2927,9 +2977,15 @@ class MediaRouter2ServiceImpl {
        public final int mOwnerPid;
        @NonNull public final String mOwnerPackageName;
        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;

        /**
         * 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 mHasMediaContentControl;
        @Nullable public SessionCreationRequest mLastSessionCreationRequest;
@@ -2943,6 +2999,7 @@ class MediaRouter2ServiceImpl {
                int ownerPid,
                @NonNull String ownerPackageName,
                @Nullable String targetPackageName,
                int targetUid,
                boolean hasMediaRoutingControl,
                boolean hasMediaContentControl) {
            mUserRecord = userRecord;
@@ -2951,6 +3008,7 @@ class MediaRouter2ServiceImpl {
            mOwnerPid = ownerPid;
            mOwnerPackageName = ownerPackageName;
            mTargetPackageName = targetPackageName;
            mTargetUid = targetUid;
            mManagerId = mNextRouterOrManagerId.getAndIncrement();
            mHasMediaRoutingControl = hasMediaRoutingControl;
            mHasMediaContentControl = hasMediaContentControl;
@@ -4147,6 +4205,14 @@ class MediaRouter2ServiceImpl {
            }
        }

        private void notifyDeviceSuggestionsClearedOnHandler(
                String routerPackageName, Set<String> suggestingPackages) {
            for (String suggestingPackage : suggestingPackages) {
                notifyDeviceSuggestionsUpdatedOnHandler(
                        routerPackageName, suggestingPackage, /* suggestedDeviceInfo= */ null);
            }
        }

        private void notifyDeviceSuggestionsUpdatedOnHandler(
                String routerPackageName,
                String suggestingPackageName,
+132 −6
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.MediaRoute2ProviderService;
import android.media.MediaRouter2;
import android.media.RouteListingPreference;
import android.media.RoutingChangeInfo;
import android.media.RoutingChangeInfo.EntryPoint;
@@ -74,6 +75,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;

/**
 * Logs metrics for MediaRouter2.
@@ -112,6 +114,18 @@ final class MediaRouterMetricLogger {
    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;
    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. */
    private final EvictionCallbackLruCache<Long, RequestInfo> mRequestInfoCache;

@@ -127,6 +141,13 @@ final class MediaRouterMetricLogger {
     */
    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}. */
    public MediaRouterMetricLogger() {
        mRequestInfoCache =
@@ -141,6 +162,9 @@ final class MediaRouterMetricLogger {
        mRlpCountCache =
                new EvictionCallbackLruCache<>(
                        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));
    }

    /**
     * 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
     * care of logging metrics aggregated over the lifecycle of the {@link
@@ -370,12 +445,8 @@ final class MediaRouterMetricLogger {
     *     android.media.MediaRouter2} instance.
     */
    public void notifyRouterUnregistered(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);
        logRlpCountForRouter(routerPackageUid);
        logDeviceSuggestionsCountForRouter(routerPackageUid);
    }

    /**
@@ -522,6 +593,15 @@ final class MediaRouterMetricLogger {
                /* 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) {
        MediaRouterStatsLog.write(
                MediaRouterStatsLog.ROUTE_LISTING_PREFERENCE_UPDATED,
@@ -530,6 +610,25 @@ final class MediaRouterMetricLogger {
                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. */
    static class RequestInfo {
        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> {
        void onEntryEvicted(K key, V value);
    }
@@ -641,4 +749,22 @@ final class MediaRouterMetricLogger {

    /** Tracks the count of changes in route listing preference */
    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) {}
}