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

Commit ddf44b23 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Use DeviceConfig in MediaMetricsManagerService" into sc-dev am: d87df180 am: d0292b71

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15027382

Change-Id: I6ed184e022116b14d54e9e50d6eeb7b5e8cf3d81
parents 49290424 d0292b71
Loading
Loading
Loading
Loading
+247 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.media.metrics;

import android.content.Context;
import android.content.pm.PackageManager;
import android.media.metrics.IMediaMetricsManager;
import android.media.metrics.NetworkEvent;
import android.media.metrics.PlaybackErrorEvent;
@@ -24,19 +25,60 @@ import android.media.metrics.PlaybackMetrics;
import android.media.metrics.PlaybackStateEvent;
import android.media.metrics.TrackChangeEvent;
import android.os.Binder;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.Base64;
import android.util.Slog;
import android.util.StatsEvent;
import android.util.StatsLog;

import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;

import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;

/**
 * System service manages media metrics.
 */
public final class MediaMetricsManagerService extends SystemService {
    private static final String TAG = "MediaMetricsManagerService";

    private static final String MEDIA_METRICS_MODE = "media_metrics_mode";
    private static final String PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST =
            "player_metrics_per_app_attribution_allowlist";
    private static final String PLAYER_METRICS_APP_ALLOWLIST = "player_metrics_app_allowlist";

    private static final String PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST =
            "player_metrics_per_app_attribution_blocklist";
    private static final String PLAYER_METRICS_APP_BLOCKLIST = "player_metrics_app_blocklist";

    private static final int MEDIA_METRICS_MODE_OFF = 0;
    private static final int MEDIA_METRICS_MODE_ON = 1;
    private static final int MEDIA_METRICS_MODE_BLOCKLIST = 2;
    private static final int MEDIA_METRICS_MODE_ALLOWLIST = 3;

    // Cascading logging levels. The higher value, the more constrains (less logging data).
    // The unused values between 2 consecutive levels are reserved for potential extra levels.
    private static final int LOGGING_LEVEL_EVERYTHING = 0;
    private static final int LOGGING_LEVEL_NO_UID = 1000;
    private static final int LOGGING_LEVEL_BLOCKED = 99999;

    private static final String FAILED_TO_GET = "failed_to_get";
    private final SecureRandom mSecureRandom;
    @GuardedBy("mLock")
    private Integer mMode = null;
    @GuardedBy("mLock")
    private List<String> mAllowlist = null;
    @GuardedBy("mLock")
    private List<String> mNoUidAllowlist = null;
    @GuardedBy("mLock")
    private List<String> mBlockList = null;
    @GuardedBy("mLock")
    private List<String> mNoUidBlocklist = null;
    private final Object mLock = new Object();
    private final Context mContext;

    /**
     * Initializes the playback metrics manager service.
@@ -45,20 +87,73 @@ public final class MediaMetricsManagerService extends SystemService {
     */
    public MediaMetricsManagerService(Context context) {
        super(context);
        mContext = context;
        mSecureRandom = new SecureRandom();
    }

    @Override
    public void onStart() {
        publishBinderService(Context.MEDIA_METRICS_SERVICE, new BinderService());
        DeviceConfig.addOnPropertiesChangedListener(
                DeviceConfig.NAMESPACE_MEDIA,
                mContext.getMainExecutor(),
                this::updateConfigs);
    }

    private void updateConfigs(Properties properties) {
        synchronized (mLock) {
            mMode = properties.getInt(
                    MEDIA_METRICS_MODE,
                    MEDIA_METRICS_MODE_BLOCKLIST);
            List<String> newList = getListLocked(PLAYER_METRICS_APP_ALLOWLIST);
            if (newList != null || mMode != MEDIA_METRICS_MODE_ALLOWLIST) {
                // don't overwrite the list if the mode IS MEDIA_METRICS_MODE_ALLOWLIST
                // but failed to get
                mAllowlist = newList;
            }
            newList = getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
            if (newList != null || mMode != MEDIA_METRICS_MODE_ALLOWLIST) {
                mNoUidAllowlist = newList;
            }
            newList = getListLocked(PLAYER_METRICS_APP_BLOCKLIST);
            if (newList != null || mMode != MEDIA_METRICS_MODE_BLOCKLIST) {
                mBlockList = newList;
            }
            newList = getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
            if (newList != null || mMode != MEDIA_METRICS_MODE_BLOCKLIST) {
                mNoUidBlocklist = newList;
            }
        }
    }

    @GuardedBy("mLock")
    private List<String> getListLocked(String listName) {
        final long identity = Binder.clearCallingIdentity();
        String listString = FAILED_TO_GET;
        try {
            listString = DeviceConfig.getString(
                    DeviceConfig.NAMESPACE_MEDIA, listName, FAILED_TO_GET);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
        if (listString.equals(FAILED_TO_GET)) {
            Slog.d(TAG, "failed to get " + listName + " from DeviceConfig");
            return null;
        }
        String[] pkgArr = listString.split(",");
        return Arrays.asList(pkgArr);
    }

    private final class BinderService extends IMediaMetricsManager.Stub {
        @Override
        public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
            int level = loggingLevel();
            if (level == LOGGING_LEVEL_BLOCKED) {
                return;
            }
            StatsEvent statsEvent = StatsEvent.newBuilder()
                    .setAtomId(320)
                    .writeInt(Binder.getCallingUid())
                    .writeInt(level == LOGGING_LEVEL_EVERYTHING ? Binder.getCallingUid() : 0)
                    .writeString(sessionId)
                    .writeLong(metrics.getMediaDurationMillis())
                    .writeInt(metrics.getStreamSource())
@@ -85,6 +180,10 @@ public final class MediaMetricsManagerService extends SystemService {
        @Override
        public void reportPlaybackStateEvent(
                String sessionId, PlaybackStateEvent event, int userId) {
            int level = loggingLevel();
            if (level == LOGGING_LEVEL_BLOCKED) {
                return;
            }
            StatsEvent statsEvent = StatsEvent.newBuilder()
                    .setAtomId(322)
                    .writeString(sessionId)
@@ -116,6 +215,10 @@ public final class MediaMetricsManagerService extends SystemService {
        @Override
        public void reportPlaybackErrorEvent(
                String sessionId, PlaybackErrorEvent event, int userId) {
            int level = loggingLevel();
            if (level == LOGGING_LEVEL_BLOCKED) {
                return;
            }
            StatsEvent statsEvent = StatsEvent.newBuilder()
                    .setAtomId(323)
                    .writeString(sessionId)
@@ -130,6 +233,10 @@ public final class MediaMetricsManagerService extends SystemService {

        public void reportNetworkEvent(
                String sessionId, NetworkEvent event, int userId) {
            int level = loggingLevel();
            if (level == LOGGING_LEVEL_BLOCKED) {
                return;
            }
            StatsEvent statsEvent = StatsEvent.newBuilder()
                    .setAtomId(321)
                    .writeString(sessionId)
@@ -143,6 +250,10 @@ public final class MediaMetricsManagerService extends SystemService {
        @Override
        public void reportTrackChangeEvent(
                String sessionId, TrackChangeEvent event, int userId) {
            int level = loggingLevel();
            if (level == LOGGING_LEVEL_BLOCKED) {
                return;
            }
            StatsEvent statsEvent = StatsEvent.newBuilder()
                    .setAtomId(324)
                    .writeString(sessionId)
@@ -165,5 +276,140 @@ public final class MediaMetricsManagerService extends SystemService {
                    .build();
            StatsLog.write(statsEvent);
        }

        private int loggingLevel() {
            synchronized (mLock) {
                int uid = Binder.getCallingUid();

                if (mMode == null) {
                    final long identity = Binder.clearCallingIdentity();
                    try {
                        mMode = DeviceConfig.getInt(
                            DeviceConfig.NAMESPACE_MEDIA,
                            MEDIA_METRICS_MODE,
                            MEDIA_METRICS_MODE_BLOCKLIST);
                    } finally {
                        Binder.restoreCallingIdentity(identity);
                    }
                }

                if (mMode == MEDIA_METRICS_MODE_ON) {
                    return LOGGING_LEVEL_EVERYTHING;
                }
                if (mMode == MEDIA_METRICS_MODE_OFF) {
                    return LOGGING_LEVEL_BLOCKED;
                }

                PackageManager pm = getContext().getPackageManager();
                String[] packages = pm.getPackagesForUid(uid);
                if (packages == null || packages.length == 0) {
                    // The valid application UID range is from
                    // android.os.Process.FIRST_APPLICATION_UID to
                    // android.os.Process.LAST_APPLICATION_UID.
                    // UIDs outside this range will not have a package.
                    Slog.d(TAG, "empty package from uid " + uid);
                    // block the data if the mode is MEDIA_METRICS_MODE_ALLOWLIST
                    return mMode == MEDIA_METRICS_MODE_BLOCKLIST
                            ? LOGGING_LEVEL_NO_UID : LOGGING_LEVEL_BLOCKED;
                }
                if (mMode == MEDIA_METRICS_MODE_BLOCKLIST) {
                    if (mBlockList == null) {
                        mBlockList = getListLocked(PLAYER_METRICS_APP_BLOCKLIST);
                        if (mBlockList == null) {
                            // failed to get the blocklist. Block it.
                            return LOGGING_LEVEL_BLOCKED;
                        }
                    }
                    Integer level = loggingLevelInternal(
                            packages, mBlockList, PLAYER_METRICS_APP_BLOCKLIST);
                    if (level != null) {
                        return level;
                    }
                    if (mNoUidBlocklist == null) {
                        mNoUidBlocklist =
                                getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
                        if (mNoUidBlocklist == null) {
                            // failed to get the blocklist. Block it.
                            return LOGGING_LEVEL_BLOCKED;
                        }
                    }
                    level = loggingLevelInternal(
                            packages,
                            mNoUidBlocklist,
                            PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST);
                    if (level != null) {
                        return level;
                    }
                    // Not detected in any blocklist. Log everything.
                    return LOGGING_LEVEL_EVERYTHING;
                }
                if (mMode == MEDIA_METRICS_MODE_ALLOWLIST) {
                    if (mNoUidAllowlist == null) {
                        mNoUidAllowlist =
                                getListLocked(PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
                        if (mNoUidAllowlist == null) {
                            // failed to get the allowlist. Block it.
                            return LOGGING_LEVEL_BLOCKED;
                        }
                    }
                    Integer level = loggingLevelInternal(
                            packages,
                            mNoUidAllowlist,
                            PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST);
                    if (level != null) {
                        return level;
                    }
                    if (mAllowlist == null) {
                        mAllowlist = getListLocked(PLAYER_METRICS_APP_ALLOWLIST);
                        if (mAllowlist == null) {
                            // failed to get the allowlist. Block it.
                            return LOGGING_LEVEL_BLOCKED;
                        }
                    }
                    level = loggingLevelInternal(
                            packages, mAllowlist, PLAYER_METRICS_APP_ALLOWLIST);
                    if (level != null) {
                        return level;
                    }
                    // Not detected in any allowlist. Block.
                    return LOGGING_LEVEL_BLOCKED;
                }
            }
            // Blocked by default.
            return LOGGING_LEVEL_BLOCKED;
        }

        private Integer loggingLevelInternal(
                String[] packages, List<String> cached, String listName) {
            if (inList(packages, cached)) {
                return listNameToLoggingLevel(listName);
            }
            return null;
        }

        private boolean inList(String[] packages, List<String> arr) {
            for (String p : packages) {
                for (String element : arr) {
                    if (p.equals(element)) {
                        return true;
                    }
                }
            }
            return false;
        }

        private int listNameToLoggingLevel(String listName) {
            switch (listName) {
                case PLAYER_METRICS_APP_BLOCKLIST:
                    return LOGGING_LEVEL_BLOCKED;
                case PLAYER_METRICS_APP_ALLOWLIST:
                    return LOGGING_LEVEL_EVERYTHING;
                case PLAYER_METRICS_PER_APP_ATTRIBUTION_ALLOWLIST:
                case PLAYER_METRICS_PER_APP_ATTRIBUTION_BLOCKLIST:
                    return LOGGING_LEVEL_NO_UID;
                default:
                    return LOGGING_LEVEL_BLOCKED;
            }
        }
    }
}