Set/get allowed capture policy via AudioService.
Do not call AudioSystem.setAllowedCapturePolicy directly in AudioManager. Instead, send the request to AudioService and calling the function in AudioService. In that case, AudioService can cached the request so that it benefits returning correct playback configuration. When querying capture policy, AudioManager will query AudioService first to see if there is cached capture policy. If there is exception, return cached capture policy in AudioManager. Test: dumpsys audio, query active audio playback configuration Test: atest AudioManagerTest, AudioAttributesTest Test: atest AudioPlaybackCaptureTest, AudioPlaybackConfigurationTest Bug: 145115448 Change-Id: I170571d8a67839bc5a53991d6c89127b99b5c794
This commit is contained in:
@@ -1427,7 +1427,10 @@ public final class AudioAttributes implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
|
||||||
switch (capturePolicy) {
|
switch (capturePolicy) {
|
||||||
case ALLOW_CAPTURE_BY_NONE:
|
case ALLOW_CAPTURE_BY_NONE:
|
||||||
flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
|
flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
|
||||||
|
|||||||
@@ -1547,23 +1547,22 @@ public class AudioManager {
|
|||||||
* {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
|
||||||
* {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
|
||||||
* {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
|
||||||
* @throws IllegalArgumentException if the argument is not a valid value.
|
* @throws RuntimeException if the argument is not a valid value.
|
||||||
*/
|
*/
|
||||||
public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
|
public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
|
||||||
int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
|
|
||||||
// TODO: got trough AudioService and save a cache to restore in case of AP crash
|
|
||||||
// TODO: also pass the package in case multiple packages have the same UID
|
// TODO: also pass the package in case multiple packages have the same UID
|
||||||
int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
|
final IAudioService service = getService();
|
||||||
if (result != AudioSystem.AUDIO_STATUS_OK) {
|
try {
|
||||||
Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
|
int result = service.setAllowedCapturePolicy(capturePolicy);
|
||||||
return;
|
if (result != AudioSystem.AUDIO_STATUS_OK) {
|
||||||
|
Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
mCapturePolicy = capturePolicy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AudioAttributes.CapturePolicy
|
|
||||||
private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the capture policy.
|
* Return the capture policy.
|
||||||
* @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
|
* @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
|
||||||
@@ -1571,7 +1570,13 @@ public class AudioManager {
|
|||||||
*/
|
*/
|
||||||
@AudioAttributes.CapturePolicy
|
@AudioAttributes.CapturePolicy
|
||||||
public int getAllowedCapturePolicy() {
|
public int getAllowedCapturePolicy() {
|
||||||
return mCapturePolicy;
|
int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
|
||||||
|
try {
|
||||||
|
result = getService().getAllowedCapturePolicy();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Failed to query allowed capture policy: " + e);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//====================================================================
|
//====================================================================
|
||||||
|
|||||||
@@ -282,6 +282,10 @@ interface IAudioService {
|
|||||||
|
|
||||||
List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes);
|
List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes);
|
||||||
|
|
||||||
|
int setAllowedCapturePolicy(in int capturePolicy);
|
||||||
|
|
||||||
|
int getAllowedCapturePolicy();
|
||||||
|
|
||||||
// WARNING: read warning at top of file, new methods that need to be used by native
|
// WARNING: read warning at top of file, new methods that need to be used by native
|
||||||
// code via IAudioManager.h need to be added to the top section.
|
// code via IAudioManager.h need to be added to the top section.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1068,6 +1068,27 @@ public class AudioService extends IAudioService.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore capture policies
|
||||||
|
synchronized (mPlaybackMonitor) {
|
||||||
|
HashMap<Integer, Integer> allowedCapturePolicies =
|
||||||
|
mPlaybackMonitor.getAllAllowedCapturePolicies();
|
||||||
|
for (HashMap.Entry<Integer, Integer> entry : allowedCapturePolicies.entrySet()) {
|
||||||
|
int result = AudioSystem.setAllowedCapturePolicy(
|
||||||
|
entry.getKey(),
|
||||||
|
AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0));
|
||||||
|
if (result != AudioSystem.AUDIO_STATUS_OK) {
|
||||||
|
Log.e(TAG, "Failed to restore capture policy, uid: "
|
||||||
|
+ entry.getKey() + ", capture policy: " + entry.getValue()
|
||||||
|
+ ", result: " + result);
|
||||||
|
// When restoring capture policy failed, set the capture policy as
|
||||||
|
// ALLOW_CAPTURE_BY_ALL, which will result in removing the cached
|
||||||
|
// capture policy in PlaybackActivityMonitor.
|
||||||
|
mPlaybackMonitor.setAllowedCapturePolicy(
|
||||||
|
entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onIndicateSystemReady();
|
onIndicateSystemReady();
|
||||||
// indicate the end of reconfiguration phase to audio HAL
|
// indicate the end of reconfiguration phase to audio HAL
|
||||||
AudioSystem.setParameters("restarting=false");
|
AudioSystem.setParameters("restarting=false");
|
||||||
@@ -7298,6 +7319,43 @@ public class AudioService extends IAudioService.Stub
|
|||||||
mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
|
mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the audio played by this app may or may not be captured by other apps or
|
||||||
|
* the system.
|
||||||
|
*
|
||||||
|
* @param capturePolicy one of
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
|
||||||
|
* @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed.
|
||||||
|
* @throws IllegalArgumentException if the argument is not a valid value.
|
||||||
|
*/
|
||||||
|
public int setAllowedCapturePolicy(int capturePolicy) {
|
||||||
|
int callingUid = Binder.getCallingUid();
|
||||||
|
int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
synchronized (mPlaybackMonitor) {
|
||||||
|
int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags);
|
||||||
|
if (result == AudioSystem.AUDIO_STATUS_OK) {
|
||||||
|
mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy);
|
||||||
|
}
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the capture policy.
|
||||||
|
* @return the cached capture policy for the calling uid.
|
||||||
|
*/
|
||||||
|
public int getAllowedCapturePolicy() {
|
||||||
|
int callingUid = Binder.getCallingUid();
|
||||||
|
final long identity = Binder.clearCallingIdentity();
|
||||||
|
int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid);
|
||||||
|
Binder.restoreCallingIdentity(identity);
|
||||||
|
return capturePolicy;
|
||||||
|
}
|
||||||
|
|
||||||
//======================
|
//======================
|
||||||
// Audio device management
|
// Audio device management
|
||||||
//======================
|
//======================
|
||||||
|
|||||||
@@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor
|
|||||||
new AudioPlaybackConfiguration(pic, newPiid,
|
new AudioPlaybackConfiguration(pic, newPiid,
|
||||||
Binder.getCallingUid(), Binder.getCallingPid());
|
Binder.getCallingUid(), Binder.getCallingPid());
|
||||||
apc.init();
|
apc.init();
|
||||||
|
synchronized (mAllowedCapturePolicies) {
|
||||||
|
int uid = apc.getClientUid();
|
||||||
|
if (mAllowedCapturePolicies.containsKey(uid)) {
|
||||||
|
updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid));
|
||||||
|
}
|
||||||
|
}
|
||||||
sEventLogger.log(new NewPlayerEvent(apc));
|
sEventLogger.log(new NewPlayerEvent(apc));
|
||||||
synchronized(mPlayerLock) {
|
synchronized(mPlayerLock) {
|
||||||
mPlayers.put(newPiid, apc);
|
mPlayers.put(newPiid, apc);
|
||||||
@@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor
|
|||||||
|
|
||||||
public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
|
public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
|
||||||
final boolean change;
|
final boolean change;
|
||||||
|
synchronized (mAllowedCapturePolicies) {
|
||||||
|
if (mAllowedCapturePolicies.containsKey(binderUid)
|
||||||
|
&& attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) {
|
||||||
|
attr = new AudioAttributes.Builder(attr)
|
||||||
|
.setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
synchronized(mPlayerLock) {
|
synchronized(mPlayerLock) {
|
||||||
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
|
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
|
||||||
if (checkConfigurationCaller(piid, apc, binderUid)) {
|
if (checkConfigurationCaller(piid, apc, binderUid)) {
|
||||||
@@ -284,6 +297,69 @@ public final class PlaybackActivityMonitor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of uid to capture policy.
|
||||||
|
*/
|
||||||
|
private final HashMap<Integer, Integer> mAllowedCapturePolicies =
|
||||||
|
new HashMap<Integer, Integer>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache allowed capture policy, which specifies whether the audio played by the app may or may
|
||||||
|
* not be captured by other apps or the system.
|
||||||
|
*
|
||||||
|
* @param uid the uid of requested app
|
||||||
|
* @param capturePolicy one of
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
|
||||||
|
* {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
|
||||||
|
*/
|
||||||
|
public void setAllowedCapturePolicy(int uid, int capturePolicy) {
|
||||||
|
synchronized (mAllowedCapturePolicies) {
|
||||||
|
if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) {
|
||||||
|
// When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to
|
||||||
|
// remove it from cached capture policy as it is the default value.
|
||||||
|
mAllowedCapturePolicies.remove(uid);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
mAllowedCapturePolicies.put(uid, capturePolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synchronized (mPlayerLock) {
|
||||||
|
for (AudioPlaybackConfiguration apc : mPlayers.values()) {
|
||||||
|
if (apc.getClientUid() == uid) {
|
||||||
|
updateAllowedCapturePolicy(apc, capturePolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the capture policy for given uid.
|
||||||
|
* @param uid the uid to query its cached capture policy.
|
||||||
|
* @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL
|
||||||
|
* if there is not cached capture policy.
|
||||||
|
*/
|
||||||
|
public int getAllowedCapturePolicy(int uid) {
|
||||||
|
return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all cached capture policies.
|
||||||
|
*/
|
||||||
|
public HashMap<Integer, Integer> getAllAllowedCapturePolicies() {
|
||||||
|
return mAllowedCapturePolicies;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) {
|
||||||
|
AudioAttributes attr = apc.getAudioAttributes();
|
||||||
|
if (attr.getAllowedCapturePolicy() >= capturePolicy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
apc.handleAudioAttributesEvent(
|
||||||
|
new AudioAttributes.Builder(apc.getAudioAttributes())
|
||||||
|
.setAllowedCapturePolicy(capturePolicy).build());
|
||||||
|
}
|
||||||
|
|
||||||
// Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
|
// Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
|
||||||
@Override
|
@Override
|
||||||
public void playerDeath(int piid) {
|
public void playerDeath(int piid) {
|
||||||
@@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor
|
|||||||
// log
|
// log
|
||||||
sEventLogger.dump(pw);
|
sEventLogger.dump(pw);
|
||||||
}
|
}
|
||||||
|
synchronized (mAllowedCapturePolicies) {
|
||||||
|
pw.println("\n allowed capture policies:");
|
||||||
|
for (HashMap.Entry<Integer, Integer> entry : mAllowedCapturePolicies.entrySet()) {
|
||||||
|
pw.println(" uid: " + entry.getKey() + " policy: " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user