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

Commit 7d6d9bd6 authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

Analyze native crash in AudioEffect via event listener

Add repro code to the EffectsTest app. Steps:
 1. Start playback on the "Environmental Reverb Test",
    memorize the session id.
 2. Enter the session id on the "Bass Boost Test" or
    the "Visualizer" tab.
 3. Press "Hammer on release()" multiple times and check
    if the app crashes. Currently this happens for
    the Bass Boost effect.

Bug: 178363662
Test: see above
Change-Id: I800bc352fc8bc7073d1523c837008dc6fcfb957a
parent 99f31b98
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -13,6 +13,10 @@
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<!--
Make sure to enable access to the mic in settings and run:
adb shell am compat enable ALLOW_TEST_API_ACCESS com.android.effectstest
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.effectstest">
+5 −0
Original line number Diff line number Diff line
@@ -187,6 +187,11 @@
                 android:layout_height="wrap_content"
                 android:scaleType="fitXY"/>

            <Button android:id="@+id/hammer_on_release_bug"
                    android:layout_width="fill_parent" android:layout_height="wrap_content"
                    android:text="@string/hammer_on_release_bug_name">
            </Button>

        </LinearLayout>

    </ScrollView>
+5 −0
Original line number Diff line number Diff line
@@ -175,6 +175,11 @@

    </LinearLayout>

    <Button android:id="@+id/hammer_on_release_bug"
            android:layout_width="fill_parent" android:layout_height="wrap_content"
            android:text="@string/hammer_on_release_bug_name">
    </Button>

    <ImageView
         android:src="@android:drawable/divider_horizontal_dark"
         android:layout_width="fill_parent"
+2 −0
Original line number Diff line number Diff line
@@ -37,4 +37,6 @@
    <string name="send_level_name">Send Level</string>
    <!-- Toggles use of a multi-threaded client for an effect [CHAR LIMIT=24] -->
    <string name="effect_multithreaded">Multithreaded Use</string>
    <!-- Runs a stress test for a bug related to simultaneous release of multiple effect instances [CHAR LIMIT=24] -->
    <string name="hammer_on_release_bug_name">Hammer on release()</string>
</resources>
+67 −13
Original line number Diff line number Diff line
@@ -17,29 +17,24 @@
package com.android.effectstest;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.BassBoost;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View.OnClickListener;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.ToggleButton;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import java.nio.ByteOrder;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;

import android.media.audiofx.BassBoost;
import android.media.audiofx.AudioEffect;

public class BassBoostTest extends Activity implements OnCheckedChangeListener {

@@ -78,6 +73,9 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
        mReleaseButton = (ToggleButton)findViewById(R.id.bbReleaseButton);
        mOnOffButton = (ToggleButton)findViewById(R.id.bassboostOnOff);

        final Button hammerReleaseTest = (Button) findViewById(R.id.hammer_on_release_bug);
        hammerReleaseTest.setEnabled(false);

        getEffect(sSession);

        if (mBassBoost != null) {
@@ -93,6 +91,14 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
            mStrength = new BassBoostParam(mBassBoost, 0, 1000, seekBar, textView);
            seekBar.setOnSeekBarChangeListener(mStrength);
            mStrength.setEnabled(mBassBoost.getStrengthSupported());

            hammerReleaseTest.setEnabled(true);
            hammerReleaseTest.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    runHammerReleaseTest(hammerReleaseTest);
                }
            });
        }
    }

@@ -273,4 +279,52 @@ public class BassBoostTest extends Activity implements OnCheckedChangeListener {
        }
    }

    // Stress-tests releasing of AudioEffect by doing repeated creation
    // and subsequent releasing. Also forces emission of callbacks from
    // the AudioFlinger by setting a control status listener. Since all
    // effect instances are bound to the same session, the AF will
    // notify them about the change in their status. This can reveal racy
    // behavior w.r.t. releasing.
    class HammerReleaseTest extends Thread {
        private static final int NUM_EFFECTS = 10;
        private static final int NUM_ITERATIONS = 100;
        private final int mSession;
        private final Runnable mOnComplete;

        HammerReleaseTest(int session, Runnable onComplete) {
            mSession = session;
            mOnComplete = onComplete;
        }

        @Override
        public void run() {
            Log.w(TAG, "HammerReleaseTest started");
            BassBoost[] effects = new BassBoost[NUM_EFFECTS];
            for (int i = 0; i < NUM_ITERATIONS; i++) {
                for (int j = 0; j < NUM_EFFECTS; j++) {
                    effects[j] = new BassBoost(0, mSession);
                    effects[j].setControlStatusListener(mEffectListener);
                    yield();
                }
                for (int j = NUM_EFFECTS - 1; j >= 0; j--) {
                    Log.w(TAG, "HammerReleaseTest releasing effect " + (Object) effects[j]);
                    effects[j].release();
                    effects[j] = null;
                    yield();
                }
            }
            Log.w(TAG, "HammerReleaseTest ended");
            runOnUiThread(mOnComplete);
        }
    }

    private void runHammerReleaseTest(Button controlButton) {
        controlButton.setEnabled(false);
        HammerReleaseTest thread = new HammerReleaseTest(sSession,
                () -> {
                    controlButton.setEnabled(true);
                });
        thread.start();
    }

}
Loading