Merge "AudioService: refactor audio mode stack" into sc-dev am: f872f163c1

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

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Iadac8bc5d3af0335781a2edcd4f095b70b34cd2b
This commit is contained in:
Eric Laurent
2021-02-08 08:50:34 +00:00
committed by Automerger Merge Worker
3 changed files with 406 additions and 233 deletions

View File

@@ -1,4 +1,3 @@
/*
/*
* Copyright (C) 2007 The Android Open Source Project
*

View File

@@ -765,10 +765,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
return mAudioService.getVssVolumeForDevice(streamType, device);
}
/*package*/ int getModeOwnerPid() {
return mModeOwnerPid;
}
/*package*/ int getDeviceForStream(int streamType) {
return mAudioService.getDeviceForStream(streamType);
}

View File

@@ -95,6 +95,7 @@ import android.media.IVolumeController;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMetrics;
import android.media.MediaRecorder.AudioSource;
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
@@ -161,9 +162,11 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -301,6 +304,9 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
private static final int MSG_REINIT_VOLUMES = 34;
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
private static final int MSG_UPDATE_AUDIO_MODE = 36;
private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -941,6 +947,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker = new AudioDeviceBroker(mContext, this);
mRecordMonitor = new RecordingActivityMonitor(mContext);
mRecordMonitor.registerRecordingCallback(mVoiceRecordingActivityMonitor, true);
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
@@ -950,6 +957,8 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor =
new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
mPlaybackMonitor.registerPlaybackCallback(mVoicePlaybackActivityMonitor, true);
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
readAndSetLowRamDevice();
@@ -1198,12 +1207,8 @@ public class AudioService extends IAudioService.Stub
// Restore call state
synchronized (mDeviceBroker.mSetModeLock) {
if (mAudioSystem.setPhoneState(mMode, getModeOwnerUid())
== AudioSystem.AUDIO_STATUS_OK) {
mModeLogger.log(new AudioEventLogger.StringEvent(
"onAudioServerDied causes setPhoneState(" + AudioSystem.modeToString(mMode)
+ ", uid=" + getModeOwnerUid() + ")"));
}
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
mContext.getPackageName());
}
final int forSys;
synchronized (mSettingsLock) {
@@ -2991,7 +2996,7 @@ public class AudioService extends IAudioService.Stub
}
/*package*/ int getHearingAidStreamType() {
return getHearingAidStreamType(mMode);
return getHearingAidStreamType(getMode());
}
private int getHearingAidStreamType(int mode) {
@@ -3004,15 +3009,15 @@ public class AudioService extends IAudioService.Stub
// other conditions will influence the stream type choice, read on...
break;
}
if (mVoiceActive.get()) {
if (mVoicePlaybackActive.get()) {
return AudioSystem.STREAM_VOICE_CALL;
}
return AudioSystem.STREAM_MUSIC;
}
private AtomicBoolean mVoiceActive = new AtomicBoolean(false);
private AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false);
private final IPlaybackConfigDispatcher mVoiceActivityMonitor =
private final IPlaybackConfigDispatcher mVoicePlaybackActivityMonitor =
new IPlaybackConfigDispatcher.Stub() {
@Override
public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
@@ -3034,16 +3039,126 @@ public class AudioService extends IAudioService.Stub
break;
}
}
if (mVoiceActive.getAndSet(voiceActive) != voiceActive) {
if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
updateHearingAidVolumeOnVoiceActivityUpdate();
}
// Update playback active state for all apps in audio mode stack.
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period.
synchronized (mDeviceBroker.mSetModeLock) {
boolean updateAudioMode = false;
int existingMsgPolicy = SENDMSG_QUEUE;
int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
boolean wasActive = h.isActive();
h.setPlaybackActive(false);
for (AudioPlaybackConfiguration config : configs) {
final int usage = config.getAudioAttributes().getUsage();
if (config.getClientUid() == h.getUid()
&& (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
|| usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
&& config.getPlayerState()
== AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
h.setPlaybackActive(true);
break;
}
}
if (wasActive != h.isActive()) {
updateAudioMode = true;
if (h.isActive() && h == getAudioModeOwnerHandler()) {
existingMsgPolicy = SENDMSG_REPLACE;
delay = 0;
}
}
}
if (updateAudioMode) {
sendMsg(mAudioHandler,
MSG_UPDATE_AUDIO_MODE,
existingMsgPolicy,
AudioSystem.MODE_CURRENT,
android.os.Process.myPid(),
mContext.getPackageName(),
delay);
}
}
}
private final IRecordingConfigDispatcher mVoiceRecordingActivityMonitor =
new IRecordingConfigDispatcher.Stub() {
@Override
public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
sendMsg(mAudioHandler, MSG_RECORDING_CONFIG_CHANGE, SENDMSG_REPLACE,
0 /*arg1 ignored*/, 0 /*arg2 ignored*/,
configs /*obj*/, 0 /*delay*/);
}
};
private void onRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
// Update recording active state for all apps in audio mode stack.
// When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
// and request an audio mode update immediately. Upon any other change, queue the message
// and request an audio mode update after a grace period.
synchronized (mDeviceBroker.mSetModeLock) {
boolean updateAudioMode = false;
int existingMsgPolicy = SENDMSG_QUEUE;
int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
boolean wasActive = h.isActive();
h.setRecordingActive(false);
for (AudioRecordingConfiguration config : configs) {
if (config.getClientUid() == h.getUid()
&& config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
h.setRecordingActive(true);
break;
}
}
if (wasActive != h.isActive()) {
updateAudioMode = true;
if (h.isActive() && h == getAudioModeOwnerHandler()) {
existingMsgPolicy = SENDMSG_REPLACE;
delay = 0;
}
}
}
if (updateAudioMode) {
sendMsg(mAudioHandler,
MSG_UPDATE_AUDIO_MODE,
existingMsgPolicy,
AudioSystem.MODE_CURRENT,
android.os.Process.myPid(),
mContext.getPackageName(),
delay);
}
}
}
private void dumpAudioMode(PrintWriter pw) {
pw.println("\nAudio mode: ");
pw.println("- Current mode = " + AudioSystem.modeToString(getMode()));
pw.println("- Mode owner: ");
SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
if (hdlr != null) {
hdlr.dump(pw, -1);
} else {
pw.println(" None");
}
pw.println("- Mode owner stack: ");
if (mSetModeDeathHandlers.isEmpty()) {
pw.println(" Empty");
} else {
for (int i = 0; i < mSetModeDeathHandlers.size(); i++) {
mSetModeDeathHandlers.get(i).dump(pw, i);
}
}
}
private void updateHearingAidVolumeOnVoiceActivityUpdate() {
final int streamType = getHearingAidStreamType();
final int index = getStreamVolume(streamType);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
mVoiceActive.get(), streamType, index));
mVoicePlaybackActive.get(), streamType, index));
mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
}
@@ -4060,65 +4175,46 @@ public class AudioService extends IAudioService.Stub
}
/**
* Return the pid of the current audio mode owner
* @return 0 if nobody owns the mode
*/
/*package*/ int getModeOwnerPid() {
int modeOwnerPid = 0;
try {
modeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
} catch (Exception e) {
// nothing to do, modeOwnerPid is not modified
}
return modeOwnerPid;
}
/**
* Return the uid of the current audio mode owner
* @return 0 if nobody owns the mode
*/
/*package*/ int getModeOwnerUid() {
int modeOwnerUid = 0;
try {
modeOwnerUid = mSetModeDeathHandlers.get(0).getUid();
} catch (Exception e) {
// nothing to do, modeOwnerUid is not modified
}
return modeOwnerUid;
}
private class SetModeDeathHandler implements IBinder.DeathRecipient {
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
private final boolean mIsPrivileged;
private final String mPackage;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
private int mMode;
private long mUpdateTime;
private boolean mPlaybackActive = false;
private boolean mRecordingActive = false;
SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged,
String caller, int mode) {
mMode = mode;
mCb = cb;
mPid = pid;
mUid = uid;
mIsPrivileged = isPrivileged;
mPackage = caller;
mIsPrivileged = isPrivileged;
mUpdateTime = java.lang.System.currentTimeMillis();
}
public void binderDied() {
int newModeOwnerPid = 0;
synchronized (mDeviceBroker.mSetModeLock) {
Log.w(TAG, "setMode() client died");
Log.w(TAG, "SetModeDeathHandler client died");
int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) {
Log.w(TAG, "unregistered setMode() client died");
Log.w(TAG, "unregistered SetModeDeathHandler client died");
} else {
newModeOwnerPid = setModeInt(
AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, TAG);
SetModeDeathHandler h = mSetModeDeathHandlers.get(index);
mSetModeDeathHandlers.remove(index);
sendMsg(mAudioHandler,
MSG_UPDATE_AUDIO_MODE,
SENDMSG_QUEUE,
AudioSystem.MODE_CURRENT,
android.os.Process.myPid(),
mContext.getPackageName(),
0);
}
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode());
}
public int getPid() {
@@ -4127,6 +4223,7 @@ public class AudioService extends IAudioService.Stub
public void setMode(int mode) {
mMode = mode;
mUpdateTime = java.lang.System.currentTimeMillis();
}
public int getMode() {
@@ -4148,25 +4245,131 @@ public class AudioService extends IAudioService.Stub
public boolean isPrivileged() {
return mIsPrivileged;
}
public long getUpdateTime() {
return mUpdateTime;
}
public void setPlaybackActive(boolean active) {
mPlaybackActive = active;
}
public void setRecordingActive(boolean active) {
mRecordingActive = active;
}
/**
* An app is considered active if:
* - It is privileged (has MODIFY_PHONE_STATE permission)
* or
* - It requests mode MODE_IN_COMMUNICATION, and it is either playing
* or recording for VOICE_COMMUNICATION.
* or
* - It requests a mode different from MODE_IN_COMMUNICATION or MODE_NORMAL
*/
public boolean isActive() {
return mIsPrivileged
|| ((mMode == AudioSystem.MODE_IN_COMMUNICATION)
&& (mRecordingActive || mPlaybackActive))
|| mMode == AudioSystem.MODE_IN_CALL
|| mMode == AudioSystem.MODE_RINGTONE
|| mMode == AudioSystem.MODE_CALL_SCREENING;
}
public void dump(PrintWriter pw, int index) {
SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
if (index >= 0) {
pw.println(" Requester # " + (index + 1) + ":");
}
pw.println(" - Mode: " + AudioSystem.modeToString(mMode));
pw.println(" - Binder: " + mCb);
pw.println(" - Pid: " + mPid);
pw.println(" - Uid: " + mUid);
pw.println(" - Package: " + mPackage);
pw.println(" - Privileged: " + mIsPrivileged);
pw.println(" - Active: " + isActive());
pw.println(" Playback active: " + mPlaybackActive);
pw.println(" Recording active: " + mRecordingActive);
pw.println(" - update time: " + format.format(new Date(mUpdateTime)));
}
}
@GuardedBy("mDeviceBroker.mSetModeLock")
private SetModeDeathHandler getAudioModeOwnerHandler() {
// The Audio mode owner is:
// 1) the most recent privileged app in the stack
// 2) the most recent active app in the tack
SetModeDeathHandler modeOwner = null;
SetModeDeathHandler privilegedModeOwner = null;
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
if (h.isActive()) {
// privileged apps are always active
if (h.isPrivileged()) {
if (privilegedModeOwner == null
|| h.getUpdateTime() > privilegedModeOwner.getUpdateTime()) {
privilegedModeOwner = h;
}
} else {
if (modeOwner == null
|| h.getUpdateTime() > modeOwner.getUpdateTime()) {
modeOwner = h;
}
}
}
}
return privilegedModeOwner != null ? privilegedModeOwner : modeOwner;
}
/**
* Return the pid of the current audio mode owner
* @return 0 if nobody owns the mode
*/
@GuardedBy("mDeviceBroker.mSetModeLock")
/*package*/ int getModeOwnerPid() {
SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
if (hdlr != null) {
return hdlr.getPid();
}
return 0;
}
/**
* Return the uid of the current audio mode owner
* @return 0 if nobody owns the mode
*/
@GuardedBy("mDeviceBroker.mSetModeLock")
/*package*/ int getModeOwnerUid() {
SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
if (hdlr != null) {
return hdlr.getUid();
}
return 0;
}
/** @see AudioManager#setMode(int) */
public void setMode(int mode, IBinder cb, String callingPackage) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
if (DEBUG_MODE) {
Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")");
Log.v(TAG, "setMode(mode=" + mode + ", pid=" + pid
+ ", uid=" + uid + ", caller=" + callingPackage + ")");
}
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
final int callingPid = Binder.getCallingPid();
if ((mode == AudioSystem.MODE_IN_CALL) && !hasModifyPhoneStatePermission) {
Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
+ callingPid + ", uid=" + Binder.getCallingUid());
if (cb == null) {
Log.e(TAG, "setMode() called with null binder");
return;
}
if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Log.w(TAG, "setMode() invalid mode: " + mode);
return;
}
if (mode == AudioSystem.MODE_CURRENT) {
mode = getMode();
}
if (mode == AudioSystem.MODE_CALL_SCREENING && !mIsCallScreeningModeSupported) {
Log.w(TAG, "setMode(MODE_CALL_SCREENING) not permitted "
@@ -4174,171 +4377,152 @@ public class AudioService extends IAudioService.Stub
return;
}
if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED;
if ((mode == AudioSystem.MODE_IN_CALL) && !hasModifyPhoneStatePermission) {
Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
+ pid + ", uid=" + Binder.getCallingUid());
return;
}
int newModeOwnerPid;
SetModeDeathHandler currentModeHandler = null;
synchronized (mDeviceBroker.mSetModeLock) {
if (mode == AudioSystem.MODE_CURRENT) {
mode = mMode;
for (SetModeDeathHandler h : mSetModeDeathHandlers) {
if (h.getPid() == pid) {
currentModeHandler = h;
break;
}
}
int oldModeOwnerPid = getModeOwnerPid();
// Do not allow changing mode if a call is active and the requester
// does not have permission to modify phone state or is not the mode owner,
// unless returning to NORMAL mode (will not change current mode owner) or
// not changing mode in which case the mode owner will reflect the last
// requester of current mode
if (!((mode == mMode) || (mode == AudioSystem.MODE_NORMAL))
&& ((mMode == AudioSystem.MODE_IN_CALL)
|| (mMode == AudioSystem.MODE_IN_COMMUNICATION))
&& !(hasModifyPhoneStatePermission || (oldModeOwnerPid == callingPid))) {
Log.w(TAG, "setMode(" + mode + ") from pid=" + callingPid
+ ", uid=" + Binder.getCallingUid()
+ ", cannot change mode from " + mMode
+ " without permission or being mode owner");
return;
if (mode == AudioSystem.MODE_NORMAL) {
if (currentModeHandler != null) {
if (!currentModeHandler.isPrivileged()
&& currentModeHandler.getMode() == AudioSystem.MODE_IN_COMMUNICATION) {
mAudioHandler.removeEqualMessages(
MSG_CHECK_MODE_FOR_UID, currentModeHandler);
}
mSetModeDeathHandlers.remove(currentModeHandler);
if (DEBUG_MODE) {
Log.v(TAG, "setMode(" + mode + ") removing hldr for pid: " + pid);
}
try {
currentModeHandler.getBinder().unlinkToDeath(currentModeHandler, 0);
} catch (NoSuchElementException e) {
Log.w(TAG, "setMode link does not exist ...");
}
}
} else {
if (currentModeHandler != null) {
currentModeHandler.setMode(mode);
if (DEBUG_MODE) {
Log.v(TAG, "setMode(" + mode + ") updating hldr for pid: " + pid);
}
} else {
currentModeHandler = new SetModeDeathHandler(cb, pid, uid,
hasModifyPhoneStatePermission, callingPackage, mode);
// Register for client death notification
try {
cb.linkToDeath(currentModeHandler, 0);
} catch (RemoteException e) {
// Client has died!
Log.w(TAG, "setMode() could not link to " + cb + " binder death");
return;
}
mSetModeDeathHandlers.add(currentModeHandler);
if (DEBUG_MODE) {
Log.v(TAG, "setMode(" + mode + ") adding handler for pid=" + pid);
}
}
if (mode == AudioSystem.MODE_IN_COMMUNICATION) {
// Force active state when entering/updating the stack to avoid glitches when
// an app starts playing/recording after settng the audio mode,
// and send a reminder to check activity after a grace period.
if (!currentModeHandler.isPrivileged()) {
currentModeHandler.setPlaybackActive(true);
currentModeHandler.setRecordingActive(true);
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
SENDMSG_QUEUE,
0,
0,
currentModeHandler,
CHECK_MODE_FOR_UID_PERIOD_MS);
}
}
}
newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(),
hasModifyPhoneStatePermission, callingPackage);
sendMsg(mAudioHandler,
MSG_UPDATE_AUDIO_MODE,
SENDMSG_REPLACE,
mode,
pid,
callingPackage,
0);
}
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
// SCO connections not started by the application changing the mode when pid changes
mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode());
}
// setModeInt() returns a valid PID if the audio mode was successfully set to
// any mode other than NORMAL.
@GuardedBy("mDeviceBroker.mSetModeLock")
private int setModeInt(
int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage) {
if (requestedMode == AudioSystem.MODE_CURRENT) {
requestedMode = getMode();
}
int mode = AudioSystem.MODE_NORMAL;
int uid = 0;
int pid = 0;
SetModeDeathHandler currentModeHandler = getAudioModeOwnerHandler();
if (currentModeHandler != null) {
mode = currentModeHandler.getMode();
uid = currentModeHandler.getUid();
pid = currentModeHandler.getPid();
}
if (DEBUG_MODE) {
Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid
+ ", uid=" + uid + ", caller=" + caller + ")");
}
int newModeOwnerPid = 0;
if (cb == null) {
Log.e(TAG, "setModeInt() called with null binder");
return newModeOwnerPid;
Log.v(TAG, "onUpdateAudioMode() mode: " + mode + ", mMode: " + mMode
+ " requestedMode: " + requestedMode);
}
if (mode != mMode) {
final long identity = Binder.clearCallingIdentity();
int status = mAudioSystem.setPhoneState(mode, uid);
Binder.restoreCallingIdentity(identity);
if (status == AudioSystem.AUDIO_STATUS_OK) {
if (DEBUG_MODE) {
Log.v(TAG, "onUpdateAudioMode: mode successfully set to " + mode);
}
int previousMode = mMode;
mMode = mode;
// Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
mModeLogger.log(new PhoneStateEvent(requesterPackage, requesterPid,
requestedMode, pid, mode));
SetModeDeathHandler hdlr = null;
Iterator iter = mSetModeDeathHandlers.iterator();
while (iter.hasNext()) {
SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
if (h.getPid() == pid) {
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()){
hdlr = null;
}
} catch (NoSuchElementException e) {
hdlr = null;
Log.w(TAG, "link does not exist ...");
}
break;
}
}
final int oldMode = mMode;
int status = AudioSystem.AUDIO_STATUS_OK;
int actualMode;
do {
actualMode = mode;
if (mode == AudioSystem.MODE_NORMAL) {
// get new mode from client at top the list if any
if (!mSetModeDeathHandlers.isEmpty()) {
hdlr = mSetModeDeathHandlers.get(0);
cb = hdlr.getBinder();
actualMode = hdlr.getMode();
if (DEBUG_MODE) {
Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
+ hdlr.mPid);
}
}
int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
int device = getDeviceForStream(streamType);
int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true,
requesterPackage, true /*hasModifyAudioSettings*/);
updateStreamVolumeAlias(true /*updateVolumes*/, requesterPackage);
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(previousMode, mode);
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
mDeviceBroker.postSetModeOwnerPid(pid, mode);
} else {
if (hdlr == null) {
hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller);
}
// Register for client death notification
try {
cb.linkToDeath(hdlr, 0);
} catch (RemoteException e) {
// Client has died!
Log.w(TAG, "setMode() could not link to "+cb+" binder death");
}
// Last client to call setMode() is always at top of client list
// as required by SetModeDeathHandler.binderDied()
mSetModeDeathHandlers.add(0, hdlr);
hdlr.setMode(mode);
}
if (actualMode != mMode) {
final long identity = Binder.clearCallingIdentity();
status = mAudioSystem.setPhoneState(actualMode, getModeOwnerUid());
Binder.restoreCallingIdentity(identity);
if (status == AudioSystem.AUDIO_STATUS_OK) {
if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
mMode = actualMode;
} else {
if (hdlr != null) {
mSetModeDeathHandlers.remove(hdlr);
cb.unlinkToDeath(hdlr, 0);
}
// force reading new top of mSetModeDeathHandlers stack
if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
mode = AudioSystem.MODE_NORMAL;
}
} else {
status = AudioSystem.AUDIO_STATUS_OK;
}
} while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
if (status == AudioSystem.AUDIO_STATUS_OK) {
if (actualMode != AudioSystem.MODE_NORMAL) {
newModeOwnerPid = getModeOwnerPid();
if (newModeOwnerPid == 0) {
Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
}
}
// 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);
setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller,
true /*hasModifyAudioSettings*/);
updateStreamVolumeAlias(true /*updateVolumes*/, caller);
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(oldMode, actualMode);
if (actualMode == AudioSystem.MODE_IN_COMMUNICATION
&& !hdlr.isPrivileged()) {
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
SENDMSG_QUEUE,
0,
0,
hdlr,
CHECK_MODE_FOR_UID_PERIOD_MS);
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
}
return newModeOwnerPid;
}
/** @see AudioManager#getMode() */
public int getMode() {
return mMode;
synchronized (mDeviceBroker.mSetModeLock) {
SetModeDeathHandler currentModeHandler = getAudioModeOwnerHandler();
if (currentModeHandler != null) {
return currentModeHandler.getMode();
}
return AudioSystem.MODE_NORMAL;
}
}
/** cached value read from audiopolicy manager after initialization. */
@@ -5685,11 +5869,6 @@ public class AudioService extends IAudioService.Stub
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+ " (dis)connection, got " + state);
}
if (state == BluetoothProfile.STATE_CONNECTED) {
mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
} else {
mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
}
mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
device, state, suppressNoisyIntent, musicDevice, "AudioService");
}
@@ -7034,6 +7213,9 @@ public class AudioService extends IAudioService.Stub
case MSG_PLAYBACK_CONFIG_CHANGE:
onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
break;
case MSG_RECORDING_CONFIG_CHANGE:
onRecordingConfigChange((List<AudioRecordingConfiguration>) msg.obj);
break;
case MSG_BROADCAST_MICROPHONE_MUTE:
mSystemServer.sendMicrophoneMuteChangedIntent();
@@ -7044,30 +7226,19 @@ public class AudioService extends IAudioService.Stub
if (msg.obj == null) {
break;
}
// If no other app is currently owning the audio mode and
// the app corresponding to this mode death handler object is still in the
// mode owner stack but not capturing or playing audio after 3 seconds,
// remove it from the stack.
// Otherwise, check again in 3 seconds.
// Update active playback/recording for apps requesting IN_COMMUNICATION
// mode after a grace period following the mode change
SetModeDeathHandler h = (SetModeDeathHandler) msg.obj;
if (mSetModeDeathHandlers.indexOf(h) < 0) {
break;
}
if (getModeOwnerUid() != h.getUid()
|| 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;
boolean wasActive = h.isActive();
h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid()));
h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT,
android.os.Process.myPid(), mContext.getPackageName());
}
setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(),
h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID");
mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
@@ -7084,10 +7255,16 @@ public class AudioService extends IAudioService.Stub
case MSG_REINIT_VOLUMES:
onReinitVolumes((String) msg.obj);
break;
case MSG_UPDATE_A11Y_SERVICE_UIDS:
onUpdateAccessibilityServiceUids();
break;
case MSG_UPDATE_AUDIO_MODE:
synchronized (mDeviceBroker.mSetModeLock) {
onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj);
}
break;
}
}
}
@@ -8118,6 +8295,7 @@ public class AudioService extends IAudioService.Stub
dumpStreamStates(pw);
dumpVolumeGroups(pw);
dumpRingerMode(pw);
dumpAudioMode(pw);
pw.println("\nAudio routes:");
pw.print(" mMainType=0x"); pw.println(Integer.toHexString(
mDeviceBroker.getCurAudioRoutes().mainType));