Loading media/java/android/media/AudioAttributes.java +4 −1 Original line number Diff line number Diff line Loading @@ -1251,7 +1251,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) { case ALLOW_CAPTURE_BY_NONE: flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE; Loading media/java/android/media/AudioManager.java +17 −12 Original line number Diff line number Diff line Loading @@ -1507,22 +1507,21 @@ public class AudioManager { * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, * {@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) { 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 int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); final IAudioService service = getService(); try { int result = service.setAllowedCapturePolicy(capturePolicy); if (result != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); return; } mCapturePolicy = capturePolicy; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AudioAttributes.CapturePolicy private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; /** * Return the capture policy. Loading @@ -1531,7 +1530,13 @@ public class AudioManager { */ @AudioAttributes.CapturePolicy 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; } //==================================================================== Loading media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,10 @@ interface IAudioService { boolean hasHapticChannels(in Uri uri); int setAllowedCapturePolicy(in int capturePolicy); int getAllowedCapturePolicy(); // 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. } services/core/java/com/android/server/audio/AudioService.java +58 −0 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,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(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); Loading Loading @@ -7250,6 +7271,43 @@ public class AudioService extends IAudioService.Stub 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 //====================== Loading services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +82 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor new AudioPlaybackConfiguration(pic, newPiid, Binder.getCallingUid(), Binder.getCallingPid()); apc.init(); synchronized (mAllowedCapturePolicies) { int uid = apc.getClientUid(); if (mAllowedCapturePolicies.containsKey(uid)) { updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); } } sEventLogger.log(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); Loading @@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { 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) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { Loading Loading @@ -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 @Override public void playerDeath(int piid) { Loading Loading @@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor // log 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()); } } } /** Loading Loading
media/java/android/media/AudioAttributes.java +4 −1 Original line number Diff line number Diff line Loading @@ -1251,7 +1251,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) { case ALLOW_CAPTURE_BY_NONE: flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE; Loading
media/java/android/media/AudioManager.java +17 −12 Original line number Diff line number Diff line Loading @@ -1507,22 +1507,21 @@ public class AudioManager { * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, * {@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) { 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 int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); final IAudioService service = getService(); try { int result = service.setAllowedCapturePolicy(capturePolicy); if (result != AudioSystem.AUDIO_STATUS_OK) { Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); return; } mCapturePolicy = capturePolicy; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AudioAttributes.CapturePolicy private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; /** * Return the capture policy. Loading @@ -1531,7 +1530,13 @@ public class AudioManager { */ @AudioAttributes.CapturePolicy 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; } //==================================================================== Loading
media/java/android/media/IAudioService.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,10 @@ interface IAudioService { boolean hasHapticChannels(in Uri uri); int setAllowedCapturePolicy(in int capturePolicy); int getAllowedCapturePolicy(); // 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. }
services/core/java/com/android/server/audio/AudioService.java +58 −0 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,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(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); Loading Loading @@ -7250,6 +7271,43 @@ public class AudioService extends IAudioService.Stub 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 //====================== Loading
services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +82 −0 Original line number Diff line number Diff line Loading @@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor new AudioPlaybackConfiguration(pic, newPiid, Binder.getCallingUid(), Binder.getCallingPid()); apc.init(); synchronized (mAllowedCapturePolicies) { int uid = apc.getClientUid(); if (mAllowedCapturePolicies.containsKey(uid)) { updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); } } sEventLogger.log(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); Loading @@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { 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) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { Loading Loading @@ -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 @Override public void playerDeath(int piid) { Loading Loading @@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor // log 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()); } } } /** Loading