diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 84fe12eebd379..fa02a2f85a6fd 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -30,6 +30,8 @@ import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioDeviceInfo; import android.media.AudioManager; +import android.media.AudioPlaybackConfiguration; +import android.media.AudioRecordingConfiguration; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.BluetoothProfileConnectionInfo; @@ -289,37 +291,38 @@ import java.util.concurrent.atomic.AtomicBoolean; * @param on * @param eventSource for logging purposes */ - /*package*/ void setSpeakerphoneOn(IBinder cb, int pid, boolean on, String eventSource) { + /*package*/ void setSpeakerphoneOn( + IBinder cb, int uid, boolean on, boolean isPrivileged, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "setSpeakerphoneOn, on: " + on + " pid: " + pid); + Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + uid); } postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( - cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), - on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); + cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), + on, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged)); } /** * Select device for use for communication use cases. * @param cb Client binder for death detection - * @param pid Client pid + * @param uid Client uid * @param device Device selected or null to unselect. * @param eventSource for logging purposes */ private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; - /*package*/ boolean setCommunicationDevice( - IBinder cb, int pid, AudioDeviceInfo device, String eventSource) { + /*package*/ boolean setCommunicationDevice(IBinder cb, int uid, AudioDeviceInfo device, + boolean isPrivileged, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "setCommunicationDevice, device: " + device + ", pid: " + pid); + Log.v(TAG, "setCommunicationDevice, device: " + device + ", uid: " + uid); } AudioDeviceAttributes deviceAttr = (device != null) ? new AudioDeviceAttributes(device) : null; - CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, pid, deviceAttr, - device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true); + CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(cb, uid, deviceAttr, + device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, true, isPrivileged); postSetCommunicationDeviceForClient(deviceInfo); boolean status; synchronized (deviceInfo) { @@ -353,7 +356,7 @@ import java.util.concurrent.atomic.AtomicBoolean; Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo); } if (!deviceInfo.mOn) { - CommunicationRouteClient client = getCommunicationRouteClientForPid(deviceInfo.mPid); + CommunicationRouteClient client = getCommunicationRouteClientForUid(deviceInfo.mUid); if (client == null || (deviceInfo.mDevice != null && !deviceInfo.mDevice.equals(client.getDevice()))) { return false; @@ -361,22 +364,22 @@ import java.util.concurrent.atomic.AtomicBoolean; } AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null; - setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mPid, device, - deviceInfo.mScoAudioMode, deviceInfo.mEventSource); + setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mUid, device, + deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource); return true; } @GuardedBy("mDeviceStateLock") /*package*/ void setCommunicationRouteForClient( - IBinder cb, int pid, AudioDeviceAttributes device, - int scoAudioMode, String eventSource) { + IBinder cb, int uid, AudioDeviceAttributes device, + int scoAudioMode, boolean isPrivileged, String eventSource) { if (AudioService.DEBUG_COMM_RTE) { Log.v(TAG, "setCommunicationRouteForClient: device: " + device); } AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( - "setCommunicationRouteForClient for pid: " + pid - + " device: " + device + "setCommunicationRouteForClient for uid: " + uid + + " device: " + device + " isPrivileged: " + isPrivileged + " from API: " + eventSource)).printLog(TAG)); final boolean wasBtScoRequested = isBluetoothScoRequested(); @@ -385,16 +388,18 @@ import java.util.concurrent.atomic.AtomicBoolean; // Save previous client route in case of failure to start BT SCO audio AudioDeviceAttributes prevClientDevice = null; - client = getCommunicationRouteClientForPid(pid); + boolean prevPrivileged = false; + client = getCommunicationRouteClientForUid(uid); if (client != null) { prevClientDevice = client.getDevice(); + prevPrivileged = client.isPrivileged(); } if (device != null) { - client = addCommunicationRouteClient(cb, pid, device); + client = addCommunicationRouteClient(cb, uid, device, isPrivileged); if (client == null) { - Log.w(TAG, "setCommunicationRouteForClient: could not add client for pid: " - + pid + " and device: " + device); + Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: " + + uid + " and device: " + device); } } else { client = removeCommunicationRouteClient(cb, true); @@ -406,11 +411,11 @@ import java.util.concurrent.atomic.AtomicBoolean; boolean isBtScoRequested = isBluetoothScoRequested(); if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive())) { if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) { - Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for pid: " - + pid); + Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: " + + uid); // clean up or restore previous client selection if (prevClientDevice != null) { - addCommunicationRouteClient(cb, pid, prevClientDevice); + addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged); } else { removeCommunicationRouteClient(cb, true); } @@ -447,11 +452,12 @@ import java.util.concurrent.atomic.AtomicBoolean; @GuardedBy("mDeviceStateLock") private CommunicationRouteClient topCommunicationRouteClient() { for (CommunicationRouteClient crc : mCommunicationRouteClients) { - if (crc.getPid() == mAudioModeOwner.mPid) { + if (crc.getUid() == mAudioModeOwner.mUid) { return crc; } } - if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0) { + if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0 + && mCommunicationRouteClients.get(0).isActive()) { return mCommunicationRouteClients.get(0); } return null; @@ -1107,26 +1113,26 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info); } - /*package*/ void startBluetoothScoForClient(IBinder cb, int pid, int scoAudioMode, - @NonNull String eventSource) { + /*package*/ void startBluetoothScoForClient(IBinder cb, int uid, int scoAudioMode, + boolean isPrivileged, @NonNull String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "startBluetoothScoForClient, pid: " + pid); + Log.v(TAG, "startBluetoothScoForClient, uid: " + uid); } postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( - cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), - true, scoAudioMode, eventSource, false)); + cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), + true, scoAudioMode, eventSource, false, isPrivileged)); } /*package*/ void stopBluetoothScoForClient( - IBinder cb, int pid, @NonNull String eventSource) { + IBinder cb, int uid, boolean isPrivileged, @NonNull String eventSource) { if (AudioService.DEBUG_COMM_RTE) { - Log.v(TAG, "stopBluetoothScoForClient, pid: " + pid); + Log.v(TAG, "stopBluetoothScoForClient, uid: " + uid); } postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( - cb, pid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), - false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false)); + cb, uid, new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), + false, BtHelper.SCO_MODE_UNDEFINED, eventSource, false, isPrivileged)); } /*package*/ int setPreferredDevicesForStrategySync(int strategy, @@ -1367,22 +1373,24 @@ import java.util.concurrent.atomic.AtomicBoolean; /*package*/ static final class CommunicationDeviceInfo { final @NonNull IBinder mCb; // Identifies the requesting client for death handler - final int mPid; // Requester process ID + final int mUid; // Requester UID final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset. final boolean mOn; // true if setting, false if resetting final int mScoAudioMode; // only used for SCO: requested audio mode + final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission final @NonNull String mEventSource; // caller identifier for logging boolean mWaitForStatus; // true if the caller waits for a completion status (API dependent) boolean mStatus = false; // completion status only used if mWaitForStatus is true - CommunicationDeviceInfo(@NonNull IBinder cb, int pid, + CommunicationDeviceInfo(@NonNull IBinder cb, int uid, @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, - @NonNull String eventSource, boolean waitForStatus) { + @NonNull String eventSource, boolean waitForStatus, boolean isPrivileged) { mCb = cb; - mPid = pid; + mUid = uid; mDevice = device; mOn = on; mScoAudioMode = scoAudioMode; + mIsPrivileged = isPrivileged; mEventSource = eventSource; mWaitForStatus = waitForStatus; } @@ -1401,16 +1409,17 @@ import java.util.concurrent.atomic.AtomicBoolean; } return mCb.equals(((CommunicationDeviceInfo) o).mCb) - && mPid == ((CommunicationDeviceInfo) o).mPid; + && mUid == ((CommunicationDeviceInfo) o).mUid; } @Override public String toString() { return "CommunicationDeviceInfo mCb=" + mCb.toString() - + " mPid=" + mPid + + " mUid=" + mUid + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]" + " mOn=" + mOn + " mScoAudioMode=" + mScoAudioMode + + " mIsPrivileged=" + mIsPrivileged + " mEventSource=" + mEventSource + " mWaitForStatus=" + mWaitForStatus + " mStatus=" + mStatus; @@ -1507,8 +1516,7 @@ import java.util.concurrent.atomic.AtomicBoolean; pw.println("\n" + prefix + "Communication route clients:"); mCommunicationRouteClients.forEach((cl) -> { - pw.println(" " + prefix + "pid: " + cl.getPid() + " device: " - + cl.getDevice() + " cb: " + cl.getBinder()); }); + pw.println(" " + prefix + cl.toString()); }); pw.println("\n" + prefix + "Computed Preferred communication device: " + preferredCommunicationDevice()); @@ -2101,13 +2109,20 @@ import java.util.concurrent.atomic.AtomicBoolean; private class CommunicationRouteClient implements IBinder.DeathRecipient { private final IBinder mCb; - private final int mPid; + private final int mUid; + private final boolean mIsPrivileged; private AudioDeviceAttributes mDevice; + private boolean mPlaybackActive; + private boolean mRecordingActive; - CommunicationRouteClient(IBinder cb, int pid, AudioDeviceAttributes device) { + CommunicationRouteClient(IBinder cb, int uid, AudioDeviceAttributes device, + boolean isPrivileged) { mCb = cb; - mPid = pid; + mUid = uid; mDevice = device; + mIsPrivileged = isPrivileged; + mPlaybackActive = mAudioService.isPlaybackActiveForUid(uid); + mRecordingActive = mAudioService.isRecordingActiveForUid(uid); } public boolean registerDeathRecipient() { @@ -2138,13 +2153,38 @@ import java.util.concurrent.atomic.AtomicBoolean; return mCb; } - int getPid() { - return mPid; + int getUid() { + return mUid; + } + + boolean isPrivileged() { + return mIsPrivileged; } AudioDeviceAttributes getDevice() { return mDevice; } + + public void setPlaybackActive(boolean active) { + mPlaybackActive = active; + } + + public void setRecordingActive(boolean active) { + mRecordingActive = active; + } + + public boolean isActive() { + return mIsPrivileged || mRecordingActive || mPlaybackActive; + } + + @Override + public String toString() { + return "[CommunicationRouteClient: mUid: " + mUid + + " mDevice: " + mDevice.toString() + + " mIsPrivileged: " + mIsPrivileged + + " mPlaybackActive: " + mPlaybackActive + + " mRecordingActive: " + mRecordingActive + "]"; + } } // @GuardedBy("mSetModeLock") @@ -2154,8 +2194,9 @@ import java.util.concurrent.atomic.AtomicBoolean; return; } Log.w(TAG, "Communication client died"); - setCommunicationRouteForClient(client.getBinder(), client.getPid(), null, - BtHelper.SCO_MODE_UNDEFINED, "onCommunicationRouteClientDied"); + setCommunicationRouteForClient(client.getBinder(), client.getUid(), null, + BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(), + "onCommunicationRouteClientDied"); } /** @@ -2242,8 +2283,8 @@ import java.util.concurrent.atomic.AtomicBoolean; + crc + " eventSource: " + eventSource); } if (crc != null) { - setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(), - BtHelper.SCO_MODE_UNDEFINED, eventSource); + setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(), + BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource); } } @@ -2282,11 +2323,12 @@ import java.util.concurrent.atomic.AtomicBoolean; } @GuardedBy("mDeviceStateLock") - private CommunicationRouteClient addCommunicationRouteClient( - IBinder cb, int pid, AudioDeviceAttributes device) { + private CommunicationRouteClient addCommunicationRouteClient(IBinder cb, int uid, + AudioDeviceAttributes device, boolean isPrivileged) { // always insert new request at first position removeCommunicationRouteClient(cb, true); - CommunicationRouteClient client = new CommunicationRouteClient(cb, pid, device); + CommunicationRouteClient client = + new CommunicationRouteClient(cb, uid, device, isPrivileged); if (client.registerDeathRecipient()) { mCommunicationRouteClients.add(0, client); return client; @@ -2295,9 +2337,9 @@ import java.util.concurrent.atomic.AtomicBoolean; } @GuardedBy("mDeviceStateLock") - private CommunicationRouteClient getCommunicationRouteClientForPid(int pid) { + private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) { for (CommunicationRouteClient cl : mCommunicationRouteClients) { - if (cl.getPid() == pid) { + if (cl.getUid() == uid) { return cl; } } @@ -2330,6 +2372,45 @@ import java.util.concurrent.atomic.AtomicBoolean; return device; } + void updateCommunicationRouteClientsActivity( + List playbackConfigs, + List recordConfigs) { + synchronized (mSetModeLock) { + synchronized (mDeviceStateLock) { + boolean updateCommunicationRoute = false; + for (CommunicationRouteClient crc : mCommunicationRouteClients) { + boolean wasActive = crc.isActive(); + if (playbackConfigs != null) { + crc.setPlaybackActive(false); + for (AudioPlaybackConfiguration config : playbackConfigs) { + if (config.getClientUid() == crc.getUid() + && config.isActive()) { + crc.setPlaybackActive(true); + break; + } + } + } + if (recordConfigs != null) { + crc.setRecordingActive(false); + for (AudioRecordingConfiguration config : recordConfigs) { + if (config.getClientUid() == crc.getUid() + && !config.isClientSilenced()) { + crc.setRecordingActive(true); + break; + } + } + } + if (wasActive != crc.isActive()) { + updateCommunicationRoute = true; + } + } + if (updateCommunicationRoute) { + postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity"); + } + } + } + } + @Nullable UUID getDeviceSensorUuid(AudioDeviceAttributes device) { synchronized (mDeviceStateLock) { return mDeviceInventory.getDeviceSensorUuid(device); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6d390f7883c29..616c1b6dece3f 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4262,22 +4262,41 @@ public class AudioService extends IAudioService.Stub // 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. + updateAudioModeHandlers( + configs /* playbackConfigs */, null /* recordConfigs */); + mDeviceBroker.updateCommunicationRouteClientsActivity( + configs /* playbackConfigs */, null /* recordConfigs */); + } + + void updateAudioModeHandlers(List playbackConfigs, + List recordConfigs) { 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 + if (playbackConfigs != null) { + h.setPlaybackActive(false); + for (AudioPlaybackConfiguration config : playbackConfigs) { + 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; + && config.isActive()) { + h.setPlaybackActive(true); + break; + } + } + } + if (recordConfigs != null) { + h.setRecordingActive(false); + for (AudioRecordingConfiguration config : recordConfigs) { + if (config.getClientUid() == h.getUid() && !config.isClientSilenced() + && config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) { + h.setRecordingActive(true); + break; + } } } if (wasActive != h.isActive()) { @@ -4315,38 +4334,10 @@ public class AudioService extends IAudioService.Stub // 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); - } - } + updateAudioModeHandlers( + null /* playbackConfigs */, configs /* recordConfigs */); + mDeviceBroker.updateCommunicationRouteClientsActivity( + null /* playbackConfigs */, configs /* recordConfigs */); } private void dumpAudioMode(PrintWriter pw) { @@ -6299,10 +6290,12 @@ public class AudioService extends IAudioService.Stub ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) .record(); } - + final boolean isPrivileged = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { - return mDeviceBroker.setCommunicationDevice(cb, pid, device, eventSource); + return mDeviceBroker.setCommunicationDevice(cb, uid, device, isPrivileged, eventSource); } finally { Binder.restoreCallingIdentity(ident); } @@ -6348,6 +6341,9 @@ public class AudioService extends IAudioService.Stub if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { return; } + final boolean isPrivileged = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED; // for logging only final int uid = Binder.getCallingUid(); @@ -6363,9 +6359,10 @@ public class AudioService extends IAudioService.Stub .set(MediaMetrics.Property.STATE, on ? MediaMetrics.Value.ON : MediaMetrics.Value.OFF) .record(); + final long ident = Binder.clearCallingIdentity(); try { - mDeviceBroker.setSpeakerphoneOn(cb, pid, on, eventSource); + mDeviceBroker.setSpeakerphoneOn(cb, uid, on, isPrivileged, eventSource); } finally { Binder.restoreCallingIdentity(ident); } @@ -6490,7 +6487,7 @@ public class AudioService extends IAudioService.Stub .set(MediaMetrics.Property.SCO_AUDIO_MODE, BtHelper.scoAudioModeToString(scoAudioMode)) .record(); - startBluetoothScoInt(cb, pid, scoAudioMode, eventSource); + startBluetoothScoInt(cb, uid, scoAudioMode, eventSource); } @@ -6513,10 +6510,10 @@ public class AudioService extends IAudioService.Stub .set(MediaMetrics.Property.SCO_AUDIO_MODE, BtHelper.scoAudioModeToString(BtHelper.SCO_MODE_VIRTUAL_CALL)) .record(); - startBluetoothScoInt(cb, pid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource); + startBluetoothScoInt(cb, uid, BtHelper.SCO_MODE_VIRTUAL_CALL, eventSource); } - void startBluetoothScoInt(IBinder cb, int pid, int scoAudioMode, @NonNull String eventSource) { + void startBluetoothScoInt(IBinder cb, int uid, int scoAudioMode, @NonNull String eventSource) { MediaMetrics.Item mmi = new MediaMetrics.Item(MediaMetrics.Name.AUDIO_BLUETOOTH) .set(MediaMetrics.Property.EVENT, "startBluetoothScoInt") .set(MediaMetrics.Property.SCO_AUDIO_MODE, @@ -6527,9 +6524,13 @@ public class AudioService extends IAudioService.Stub mmi.set(MediaMetrics.Property.EARLY_RETURN, "permission or systemReady").record(); return; } + final boolean isPrivileged = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { - mDeviceBroker.startBluetoothScoForClient(cb, pid, scoAudioMode, eventSource); + mDeviceBroker.startBluetoothScoForClient( + cb, uid, scoAudioMode, isPrivileged, eventSource); } finally { Binder.restoreCallingIdentity(ident); } @@ -6547,9 +6548,12 @@ public class AudioService extends IAudioService.Stub final String eventSource = new StringBuilder("stopBluetoothSco()") .append(") from u/pid:").append(uid).append("/") .append(pid).toString(); + final boolean isPrivileged = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + == PackageManager.PERMISSION_GRANTED; final long ident = Binder.clearCallingIdentity(); try { - mDeviceBroker.stopBluetoothScoForClient(cb, pid, eventSource); + mDeviceBroker.stopBluetoothScoForClient(cb, uid, isPrivileged, eventSource); } finally { Binder.restoreCallingIdentity(ident); } @@ -9282,8 +9286,8 @@ public class AudioService extends IAudioService.Stub break; } boolean wasActive = h.isActive(); - h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())); - h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid())); + h.setPlaybackActive(isPlaybackActiveForUid(h.getUid())); + h.setRecordingActive(isRecordingActiveForUid(h.getUid())); if (wasActive != h.isActive()) { onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(), mContext.getPackageName(), false /*force*/); @@ -12381,6 +12385,16 @@ public class AudioService extends IAudioService.Stub } } + /* package */ + boolean isPlaybackActiveForUid(int uid) { + return mPlaybackMonitor.isPlaybackActiveForUid(uid); + } + + /* package */ + boolean isRecordingActiveForUid(int uid) { + return mRecordMonitor.isRecordingActiveForUid(uid); + } + //====================== // Audio device management //====================== diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java index 652ea52285715..4332fddf3f832 100644 --- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java +++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java @@ -227,8 +227,8 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin synchronized (mRecordStates) { for (RecordingState state : mRecordStates) { // Note: isActiveConfiguration() == true => state.getConfig() != null - if (state.isActiveConfiguration() - && state.getConfig().getClientUid() == uid) { + if (state.isActiveConfiguration() && state.getConfig().getClientUid() == uid + && !state.getConfig().isClientSilenced()) { return true; } }