Merge "Use DeviceConfig in MediaMetricsManagerService" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d87df18092
@@ -17,6 +17,7 @@
|
|||||||
package com.android.server.media.metrics;
|
package com.android.server.media.metrics;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.media.metrics.IMediaMetricsManager;
|
import android.media.metrics.IMediaMetricsManager;
|
||||||
import android.media.metrics.NetworkEvent;
|
import android.media.metrics.NetworkEvent;
|
||||||
import android.media.metrics.PlaybackErrorEvent;
|
import android.media.metrics.PlaybackErrorEvent;
|
||||||
@@ -24,19 +25,60 @@ import android.media.metrics.PlaybackMetrics;
|
|||||||
import android.media.metrics.PlaybackStateEvent;
|
import android.media.metrics.PlaybackStateEvent;
|
||||||
import android.media.metrics.TrackChangeEvent;
|
import android.media.metrics.TrackChangeEvent;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
|
import android.provider.DeviceConfig.Properties;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
import android.util.Slog;
|
||||||
import android.util.StatsEvent;
|
import android.util.StatsEvent;
|
||||||
import android.util.StatsLog;
|
import android.util.StatsLog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.server.SystemService;
|
import com.android.server.SystemService;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System service manages media metrics.
|
* System service manages media metrics.
|
||||||
*/
|
*/
|
||||||
public final class MediaMetricsManagerService extends SystemService {
|
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;
|
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.
|
* Initializes the playback metrics manager service.
|
||||||
@@ -45,20 +87,73 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
*/
|
*/
|
||||||
public MediaMetricsManagerService(Context context) {
|
public MediaMetricsManagerService(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
mContext = context;
|
||||||
mSecureRandom = new SecureRandom();
|
mSecureRandom = new SecureRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
publishBinderService(Context.MEDIA_METRICS_SERVICE, new BinderService());
|
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 {
|
private final class BinderService extends IMediaMetricsManager.Stub {
|
||||||
@Override
|
@Override
|
||||||
public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
|
public void reportPlaybackMetrics(String sessionId, PlaybackMetrics metrics, int userId) {
|
||||||
|
int level = loggingLevel();
|
||||||
|
if (level == LOGGING_LEVEL_BLOCKED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
StatsEvent statsEvent = StatsEvent.newBuilder()
|
StatsEvent statsEvent = StatsEvent.newBuilder()
|
||||||
.setAtomId(320)
|
.setAtomId(320)
|
||||||
.writeInt(Binder.getCallingUid())
|
.writeInt(level == LOGGING_LEVEL_EVERYTHING ? Binder.getCallingUid() : 0)
|
||||||
.writeString(sessionId)
|
.writeString(sessionId)
|
||||||
.writeLong(metrics.getMediaDurationMillis())
|
.writeLong(metrics.getMediaDurationMillis())
|
||||||
.writeInt(metrics.getStreamSource())
|
.writeInt(metrics.getStreamSource())
|
||||||
@@ -85,6 +180,10 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
@Override
|
@Override
|
||||||
public void reportPlaybackStateEvent(
|
public void reportPlaybackStateEvent(
|
||||||
String sessionId, PlaybackStateEvent event, int userId) {
|
String sessionId, PlaybackStateEvent event, int userId) {
|
||||||
|
int level = loggingLevel();
|
||||||
|
if (level == LOGGING_LEVEL_BLOCKED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
StatsEvent statsEvent = StatsEvent.newBuilder()
|
StatsEvent statsEvent = StatsEvent.newBuilder()
|
||||||
.setAtomId(322)
|
.setAtomId(322)
|
||||||
.writeString(sessionId)
|
.writeString(sessionId)
|
||||||
@@ -116,6 +215,10 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
@Override
|
@Override
|
||||||
public void reportPlaybackErrorEvent(
|
public void reportPlaybackErrorEvent(
|
||||||
String sessionId, PlaybackErrorEvent event, int userId) {
|
String sessionId, PlaybackErrorEvent event, int userId) {
|
||||||
|
int level = loggingLevel();
|
||||||
|
if (level == LOGGING_LEVEL_BLOCKED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
StatsEvent statsEvent = StatsEvent.newBuilder()
|
StatsEvent statsEvent = StatsEvent.newBuilder()
|
||||||
.setAtomId(323)
|
.setAtomId(323)
|
||||||
.writeString(sessionId)
|
.writeString(sessionId)
|
||||||
@@ -130,6 +233,10 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
|
|
||||||
public void reportNetworkEvent(
|
public void reportNetworkEvent(
|
||||||
String sessionId, NetworkEvent event, int userId) {
|
String sessionId, NetworkEvent event, int userId) {
|
||||||
|
int level = loggingLevel();
|
||||||
|
if (level == LOGGING_LEVEL_BLOCKED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
StatsEvent statsEvent = StatsEvent.newBuilder()
|
StatsEvent statsEvent = StatsEvent.newBuilder()
|
||||||
.setAtomId(321)
|
.setAtomId(321)
|
||||||
.writeString(sessionId)
|
.writeString(sessionId)
|
||||||
@@ -143,6 +250,10 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
@Override
|
@Override
|
||||||
public void reportTrackChangeEvent(
|
public void reportTrackChangeEvent(
|
||||||
String sessionId, TrackChangeEvent event, int userId) {
|
String sessionId, TrackChangeEvent event, int userId) {
|
||||||
|
int level = loggingLevel();
|
||||||
|
if (level == LOGGING_LEVEL_BLOCKED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
StatsEvent statsEvent = StatsEvent.newBuilder()
|
StatsEvent statsEvent = StatsEvent.newBuilder()
|
||||||
.setAtomId(324)
|
.setAtomId(324)
|
||||||
.writeString(sessionId)
|
.writeString(sessionId)
|
||||||
@@ -165,5 +276,140 @@ public final class MediaMetricsManagerService extends SystemService {
|
|||||||
.build();
|
.build();
|
||||||
StatsLog.write(statsEvent);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user