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

Commit 0ac7e561 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "AudioService: handle errors when reconnecting mixes after server crash"

parents 7a2fb04c d497edd9
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.media;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -26,6 +27,8 @@ import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.util.Log;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Map;

@@ -431,6 +434,50 @@ public class AudioSystem
    public static final int DEAD_OBJECT        = -6;
    public static final int WOULD_BLOCK        = -7;

    /** @hide */
    @IntDef({
            SUCCESS,
            ERROR,
            BAD_VALUE,
            INVALID_OPERATION,
            PERMISSION_DENIED,
            NO_INIT,
            DEAD_OBJECT,
            WOULD_BLOCK
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface AudioSystemError {}

    /**
     * Convert an int error value to its String value for readability.
     * Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h,
     * which map onto the native status_t type.
     * @param error one of the java AudioSystem errors
     * @return a human-readable string
     */
    public static String audioSystemErrorToString(@AudioSystemError int error) {
        switch(error) {
            case SUCCESS:
                return "SUCCESS";
            case ERROR:
                return "ERROR";
            case BAD_VALUE:
                return "BAD_VALUE";
            case INVALID_OPERATION:
                return "INVALID_OPERATION";
            case PERMISSION_DENIED:
                return "PERMISSION_DENIED";
            case NO_INIT:
                return "NO_INIT";
            case DEAD_OBJECT:
                return "DEAD_OBJECT";
            case WOULD_BLOCK:
                return "WOULD_BLOCK";
            default:
                return ("unknown error:" + error);
        }
    }

    /*
     * AudioPolicyService methods
     */
+4 −0
Original line number Diff line number Diff line
@@ -853,6 +853,10 @@ public class AudioPolicy {
                Log.v(TAG, "notifyVolumeAdjust: " + adjustment);
            }
        }

        public void notifyUnregistration() {
            setRegistration(null);
        }
    };

    //==================================================
+4 −0
Original line number Diff line number Diff line
@@ -34,4 +34,8 @@ oneway interface IAudioPolicyCallback {

    // callback for volume events
    void notifyVolumeAdjust(int adjustment);

    // callback for unregistration (e.g. if policy couldn't automatically be re-registered after
    // an audioserver crash)
    void notifyUnregistration();
}
+22 −12
Original line number Diff line number Diff line
@@ -1018,7 +1018,14 @@ public class AudioService extends IAudioService.Stub

        synchronized (mAudioPolicies) {
            for (AudioPolicyProxy policy : mAudioPolicies.values()) {
                policy.connectMixes();
                final int status = policy.connectMixes();
                if (status != AudioSystem.SUCCESS) {
                    // note that PERMISSION_DENIED may also indicate trouble getting to APService
                    Log.e(TAG, "onAudioServerDied: error "
                            + AudioSystem.audioSystemErrorToString(status)
                            + " when connecting mixes for policy " + policy.toLogFriendlyString());
                    policy.release();
                }
            }
        }

@@ -7007,16 +7014,8 @@ public class AudioService extends IAudioService.Stub
        }

        public void binderDied() {
            synchronized (mAudioPolicies) {
            Log.i(TAG, "audio policy " + mPolicyCallback + " died");
            release();
                mAudioPolicies.remove(mPolicyCallback.asBinder());
            }
            if (mIsVolumeController) {
                synchronized (mExtVolumeControllerLock) {
                    mExtVolumeController = null;
                }
            }
        }

        String getRegistrationId() {
@@ -7040,9 +7039,20 @@ public class AudioService extends IAudioService.Stub
                    Log.e(TAG, "Fail to unregister Audiopolicy callback from MediaProjection");
                }
            }
            if (mIsVolumeController) {
                synchronized (mExtVolumeControllerLock) {
                    mExtVolumeController = null;
                }
            }
            final long identity = Binder.clearCallingIdentity();
            AudioSystem.registerPolicyMixes(mMixes, false);
            Binder.restoreCallingIdentity(identity);
            synchronized (mAudioPolicies) {
                mAudioPolicies.remove(mPolicyCallback.asBinder());
            }
            try {
                mPolicyCallback.notifyUnregistration();
            } catch (RemoteException e) { }
        }

        boolean hasMixAffectingUsage(int usage, int excludedFlags) {
@@ -7093,7 +7103,7 @@ public class AudioService extends IAudioService.Stub
            }
        }

        int connectMixes() {
        @AudioSystem.AudioSystemError int connectMixes() {
            final long identity = Binder.clearCallingIdentity();
            int status = AudioSystem.registerPolicyMixes(mMixes, true);
            Binder.restoreCallingIdentity(identity);