diff options
5 files changed, 165 insertions, 13 deletions
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 114c0f1f6bf3..fe0c2d21d442 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -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) { case ALLOW_CAPTURE_BY_NONE: flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 861b76d2b153..7b17f9f764fb 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1547,23 +1547,22 @@ 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); - if (result != AudioSystem.AUDIO_STATUS_OK) { - Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); - return; + final IAudioService service = getService(); + try { + int result = service.setAllowedCapturePolicy(capturePolicy); + 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 set by {@link #setAllowedCapturePolicy(int)} or @@ -1571,7 +1570,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; } //==================================================================== diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 1f97be5c3f4d..64c5c05b5621 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -282,6 +282,10 @@ interface IAudioService { 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 // code via IAudioManager.h need to be added to the top section. } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8f6bd212da19..b2548af0f576 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); @@ -7298,6 +7319,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 //====================== diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index f8ba55bcd092..98f409ea98e7 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -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); @@ -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)) { @@ -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) { @@ -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()); + } + } } /** |