Merge "AudioService: Add metrics for audio mode" into rvc-dev am: 148c8bc210
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12065323 Change-Id: I7ba806f49fc9cb3b61b4de8e9a265db2044f13a8
This commit is contained in:
@@ -53,6 +53,7 @@ public class MediaMetrics {
|
||||
public static final String AUDIO_SERVICE = AUDIO + SEPARATOR + "service";
|
||||
public static final String AUDIO_VOLUME = AUDIO + SEPARATOR + "volume";
|
||||
public static final String AUDIO_VOLUME_EVENT = AUDIO_VOLUME + SEPARATOR + "event";
|
||||
public static final String AUDIO_MODE = AUDIO + SEPARATOR + "mode";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,6 +141,10 @@ public class MediaMetrics {
|
||||
public static final Key<String> REQUEST =
|
||||
createKey("request", String.class);
|
||||
|
||||
// For audio mode
|
||||
public static final Key<String> REQUESTED_MODE =
|
||||
createKey("requestedMode", String.class); // audio_mode
|
||||
|
||||
// For Bluetooth
|
||||
public static final Key<String> SCO_AUDIO_MODE =
|
||||
createKey("scoAudioMode", String.class);
|
||||
|
||||
@@ -283,6 +283,7 @@ public class AudioService extends IAudioService.Stub
|
||||
private static final int MSG_HDMI_VOLUME_CHECK = 28;
|
||||
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
|
||||
private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
|
||||
private static final int MSG_CHECK_MODE_FOR_UID = 31;
|
||||
// start of messages handled under wakelock
|
||||
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
|
||||
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
|
||||
@@ -3679,12 +3680,14 @@ public class AudioService extends IAudioService.Stub
|
||||
private final IBinder mCb; // To be notified of client's death
|
||||
private final int mPid;
|
||||
private final int mUid;
|
||||
private String mPackage;
|
||||
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
|
||||
|
||||
SetModeDeathHandler(IBinder cb, int pid, int uid) {
|
||||
SetModeDeathHandler(IBinder cb, int pid, int uid, String caller) {
|
||||
mCb = cb;
|
||||
mPid = pid;
|
||||
mUid = uid;
|
||||
mPackage = caller;
|
||||
}
|
||||
|
||||
public void binderDied() {
|
||||
@@ -3722,6 +3725,10 @@ public class AudioService extends IAudioService.Stub
|
||||
public int getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
public String getPackage() {
|
||||
return mPackage;
|
||||
}
|
||||
}
|
||||
|
||||
/** @see AudioManager#setMode(int) */
|
||||
@@ -3803,6 +3810,9 @@ public class AudioService extends IAudioService.Stub
|
||||
hdlr = h;
|
||||
// Remove from client list so that it is re-inserted at top of list
|
||||
iter.remove();
|
||||
if (hdlr.getMode() == AudioSystem.MODE_IN_COMMUNICATION) {
|
||||
mAudioHandler.removeEqualMessages(MSG_CHECK_MODE_FOR_UID, hdlr);
|
||||
}
|
||||
try {
|
||||
hdlr.getBinder().unlinkToDeath(hdlr, 0);
|
||||
if (cb != hdlr.getBinder()) {
|
||||
@@ -3833,7 +3843,7 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
} else {
|
||||
if (hdlr == null) {
|
||||
hdlr = new SetModeDeathHandler(cb, pid, uid);
|
||||
hdlr = new SetModeDeathHandler(cb, pid, uid, caller);
|
||||
}
|
||||
// Register for client death notification
|
||||
try {
|
||||
@@ -3880,6 +3890,7 @@ public class AudioService extends IAudioService.Stub
|
||||
// Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
|
||||
mModeLogger.log(
|
||||
new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
|
||||
|
||||
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
|
||||
int device = getDeviceForStream(streamType);
|
||||
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
|
||||
@@ -3890,6 +3901,16 @@ public class AudioService extends IAudioService.Stub
|
||||
|
||||
// change of mode may require volume to be re-applied on some devices
|
||||
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
|
||||
|
||||
if (actualMode == AudioSystem.MODE_IN_COMMUNICATION) {
|
||||
sendMsg(mAudioHandler,
|
||||
MSG_CHECK_MODE_FOR_UID,
|
||||
SENDMSG_QUEUE,
|
||||
0,
|
||||
0,
|
||||
hdlr,
|
||||
CHECK_MODE_FOR_UID_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
return newModeOwnerPid;
|
||||
}
|
||||
@@ -6374,6 +6395,35 @@ public class AudioService extends IAudioService.Stub
|
||||
case MSG_BROADCAST_MICROPHONE_MUTE:
|
||||
mSystemServer.sendMicrophoneMuteChangedIntent();
|
||||
break;
|
||||
|
||||
case MSG_CHECK_MODE_FOR_UID:
|
||||
synchronized (mDeviceBroker.mSetModeLock) {
|
||||
if (msg.obj == null) {
|
||||
break;
|
||||
}
|
||||
// If the app corresponding to this mode death handler object is not
|
||||
// capturing or playing audio anymore after 3 seconds, remove it
|
||||
// from the stack. Otherwise, check again in 3 seconds.
|
||||
SetModeDeathHandler h = (SetModeDeathHandler) msg.obj;
|
||||
if (mSetModeDeathHandlers.indexOf(h) < 0) {
|
||||
break;
|
||||
}
|
||||
if (mRecordMonitor.isRecordingActiveForUid(h.getUid())
|
||||
|| mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())) {
|
||||
sendMsg(mAudioHandler,
|
||||
MSG_CHECK_MODE_FOR_UID,
|
||||
SENDMSG_QUEUE,
|
||||
0,
|
||||
0,
|
||||
h,
|
||||
CHECK_MODE_FOR_UID_PERIOD_MS);
|
||||
break;
|
||||
}
|
||||
// For now just log the fact that an app is hogging the audio mode.
|
||||
// TODO(b/160260850): remove abusive app from audio mode stack.
|
||||
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7017,6 +7067,8 @@ public class AudioService extends IAudioService.Stub
|
||||
private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
|
||||
private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
|
||||
private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
|
||||
// check playback or record activity every 3 seconds for UIDs owning mode IN_COMMUNICATION
|
||||
private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 3000;
|
||||
|
||||
private int safeMediaVolumeIndex(int device) {
|
||||
if (!mSafeMediaVolumeDevices.contains(device)) {
|
||||
|
||||
@@ -27,28 +27,82 @@ import com.android.server.audio.AudioDeviceInventory.WiredDeviceConnectionState;
|
||||
public class AudioServiceEvents {
|
||||
|
||||
final static class PhoneStateEvent extends AudioEventLogger.Event {
|
||||
static final int MODE_SET = 0;
|
||||
static final int MODE_IN_COMMUNICATION_TIMEOUT = 1;
|
||||
|
||||
final int mOp;
|
||||
final String mPackage;
|
||||
final int mOwnerPid;
|
||||
final int mRequesterPid;
|
||||
final int mRequestedMode;
|
||||
final int mActualMode;
|
||||
|
||||
/** used for MODE_SET */
|
||||
PhoneStateEvent(String callingPackage, int requesterPid, int requestedMode,
|
||||
int ownerPid, int actualMode) {
|
||||
mOp = MODE_SET;
|
||||
mPackage = callingPackage;
|
||||
mRequesterPid = requesterPid;
|
||||
mRequestedMode = requestedMode;
|
||||
mOwnerPid = ownerPid;
|
||||
mActualMode = actualMode;
|
||||
logMetricEvent();
|
||||
}
|
||||
|
||||
/** used for MODE_IN_COMMUNICATION_TIMEOUT */
|
||||
PhoneStateEvent(String callingPackage, int ownerPid) {
|
||||
mOp = MODE_IN_COMMUNICATION_TIMEOUT;
|
||||
mPackage = callingPackage;
|
||||
mOwnerPid = ownerPid;
|
||||
mRequesterPid = 0;
|
||||
mRequestedMode = 0;
|
||||
mActualMode = 0;
|
||||
logMetricEvent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String eventToString() {
|
||||
return new StringBuilder("setMode(").append(AudioSystem.modeToString(mRequestedMode))
|
||||
.append(") from package=").append(mPackage)
|
||||
.append(" pid=").append(mRequesterPid)
|
||||
.append(" selected mode=").append(AudioSystem.modeToString(mActualMode))
|
||||
.append(" by pid=").append(mOwnerPid).toString();
|
||||
switch (mOp) {
|
||||
case MODE_SET:
|
||||
return new StringBuilder("setMode(")
|
||||
.append(AudioSystem.modeToString(mRequestedMode))
|
||||
.append(") from package=").append(mPackage)
|
||||
.append(" pid=").append(mRequesterPid)
|
||||
.append(" selected mode=")
|
||||
.append(AudioSystem.modeToString(mActualMode))
|
||||
.append(" by pid=").append(mOwnerPid).toString();
|
||||
case MODE_IN_COMMUNICATION_TIMEOUT:
|
||||
return new StringBuilder("mode IN COMMUNICATION timeout")
|
||||
.append(" for package=").append(mPackage)
|
||||
.append(" pid=").append(mOwnerPid).toString();
|
||||
default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Audio Analytics unique Id.
|
||||
*/
|
||||
private static final String mMetricsId = MediaMetrics.Name.AUDIO_MODE;
|
||||
|
||||
private void logMetricEvent() {
|
||||
switch (mOp) {
|
||||
case MODE_SET:
|
||||
new MediaMetrics.Item(mMetricsId)
|
||||
.set(MediaMetrics.Property.EVENT, "set")
|
||||
.set(MediaMetrics.Property.REQUESTED_MODE,
|
||||
AudioSystem.modeToString(mRequestedMode))
|
||||
.set(MediaMetrics.Property.MODE, AudioSystem.modeToString(mActualMode))
|
||||
.set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
|
||||
.record();
|
||||
return;
|
||||
case MODE_IN_COMMUNICATION_TIMEOUT:
|
||||
new MediaMetrics.Item(mMetricsId)
|
||||
.set(MediaMetrics.Property.EVENT, "inCommunicationTimeout")
|
||||
.set(MediaMetrics.Property.CALLING_PACKAGE, mPackage)
|
||||
.record();
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,23 @@ public final class PlaybackActivityMonitor
|
||||
releasePlayer(piid, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a player belonging to the app with given uid is active.
|
||||
*
|
||||
* @param uid the app uid
|
||||
* @return true if a player is active, false otherwise
|
||||
*/
|
||||
public boolean isPlaybackActiveForUid(int uid) {
|
||||
synchronized (mPlayerLock) {
|
||||
for (AudioPlaybackConfiguration apc : mPlayers.values()) {
|
||||
if (apc.isActive() && apc.getClientUid() == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void dump(PrintWriter pw) {
|
||||
// players
|
||||
pw.println("\nPlaybackActivityMonitor dump time: "
|
||||
|
||||
@@ -215,6 +215,25 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
|
||||
dispatchCallbacks(updateSnapshot(AudioManager.RECORD_CONFIG_EVENT_RELEASE, riid, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a recorder belonging to the app with given uid is active.
|
||||
*
|
||||
* @param uid the app uid
|
||||
* @return true if a recorder is active, false otherwise
|
||||
*/
|
||||
public boolean isRecordingActiveForUid(int uid) {
|
||||
synchronized (mRecordStates) {
|
||||
for (RecordingState state : mRecordStates) {
|
||||
// Note: isActiveConfiguration() == true => state.getConfig() != null
|
||||
if (state.isActiveConfiguration()
|
||||
&& state.getConfig().getClientUid() == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void dispatchCallbacks(List<AudioRecordingConfiguration> configs) {
|
||||
if (configs == null) { // null means "no changes"
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user