Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55e8fd23 authored by jiabin's avatar jiabin Committed by Nadav Bar
Browse files

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
Merged-In: I170571d8a67839bc5a53991d6c89127b99b5c794
(cherry picked from commit b33f3697)
parent d9d21afd
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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;
+17 −12
Original line number Diff line number Diff line
@@ -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.
@@ -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;
    }

    //====================================================================
+4 −0
Original line number Diff line number Diff line
@@ -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.
}
+58 −0
Original line number Diff line number Diff line
@@ -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");
@@ -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
    //======================
+82 −0
Original line number Diff line number Diff line
@@ -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());
            }
        }
    }

    /**