Fix CTS mediacodec test and add test
The mediacodec-based test could pass when mediaserver crashed, because
it wasn't explicitly checking for it.
Add test for mpeg2ts extractor crash.
Bug: 28333006
Change-Id: Ib6f66b2baa3deb2478de48229e9452b55dc1ce69
diff --git a/tests/tests/security/res/raw/bug_28333006.mp2 b/tests/tests/security/res/raw/bug_28333006.mp2
new file mode 100644
index 0000000..2e3585f
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_28333006.mp2
Binary files differ
diff --git a/tests/tests/security/res/raw/good.mp3 b/tests/tests/security/res/raw/good.mp3
new file mode 100644
index 0000000..d20f772
--- /dev/null
+++ b/tests/tests/security/res/raw/good.mp3
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 8e7acac..3bbad2f 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -152,6 +152,10 @@
doStagefrightTest(R.raw.cve_2015_3873_b_21814993);
}
+ public void testStagefright_bug_28333006() throws Exception {
+ doStagefrightTest(R.raw.bug_28333006);
+ }
+
private void doStagefrightTest(final int rid) throws Exception {
doStagefrightTestMediaPlayer(rid);
doStagefrightTestMediaCodec(rid);
@@ -183,81 +187,83 @@
return new Surface(surfaceTex);
}
- private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
- class MediaPlayerCrashListener
- implements MediaPlayer.OnErrorListener,
- MediaPlayer.OnPreparedListener,
- MediaPlayer.OnCompletionListener {
- @Override
- public boolean onError(MediaPlayer mp, int newWhat, int extra) {
- Log.i(TAG, "error: " + newWhat);
- // don't overwrite a more severe error with a less severe one
- if (what != MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
- what = newWhat;
- }
- lock.lock();
- condition.signal();
- lock.unlock();
-
- return true; // don't call oncompletion
+ class MediaPlayerCrashListener
+ implements MediaPlayer.OnErrorListener,
+ MediaPlayer.OnPreparedListener,
+ MediaPlayer.OnCompletionListener {
+ @Override
+ public boolean onError(MediaPlayer mp, int newWhat, int extra) {
+ Log.i(TAG, "error: " + newWhat + "/" + extra);
+ // don't overwrite a more severe error with a less severe one
+ if (what != MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
+ what = newWhat;
}
+ lock.lock();
+ condition.signal();
+ lock.unlock();
- @Override
- public void onPrepared(MediaPlayer mp) {
- mp.start();
- }
-
- @Override
- public void onCompletion(MediaPlayer mp) {
- // preserve error condition, if any
- lock.lock();
- condition.signal();
- lock.unlock();
- }
-
- public int waitForError() throws InterruptedException {
- lock.lock();
- if (condition.awaitNanos(TIMEOUT_NS) <= 0) {
- Log.d(TAG, "timed out on waiting for error");
- }
- lock.unlock();
- if (what != 0) {
- // Sometimes mediaserver signals a decoding error first, and *then* crashes
- // due to additional in-flight buffers being processed, so wait a little
- // and see if more errors show up.
- SystemClock.sleep(1000);
- }
- return what;
- }
-
- ReentrantLock lock = new ReentrantLock();
- Condition condition = lock.newCondition();
- int what;
+ return true; // don't call oncompletion
}
+ @Override
+ public void onPrepared(MediaPlayer mp) {
+ mp.start();
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ // preserve error condition, if any
+ lock.lock();
+ condition.signal();
+ lock.unlock();
+ }
+
+ public int waitForError() throws InterruptedException {
+ lock.lock();
+ if (condition.awaitNanos(TIMEOUT_NS) <= 0) {
+ Log.d(TAG, "timed out on waiting for error");
+ }
+ lock.unlock();
+ if (what != 0) {
+ // Sometimes mediaserver signals a decoding error first, and *then* crashes
+ // due to additional in-flight buffers being processed, so wait a little
+ // and see if more errors show up.
+ SystemClock.sleep(1000);
+ }
+ return what;
+ }
+
+ ReentrantLock lock = new ReentrantLock();
+ Condition condition = lock.newCondition();
+ int what;
+ }
+
+ class LooperThread extends Thread {
+ private Looper mLooper;
+
+ LooperThread(Runnable runner) {
+ super(runner);
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ super.run();
+ }
+
+ public void stopLooper() {
+ mLooper.quitSafely();
+ }
+ }
+
+ private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
+
String name = getInstrumentation().getContext().getResources().getResourceEntryName(rid);
Log.i(TAG, "start mediaplayer test for: " + name);
final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
- class LooperThread extends Thread {
- private Looper mLooper;
-
- LooperThread(Runnable runner) {
- super(runner);
- }
-
- @Override
- public void run() {
- Looper.prepare();
- mLooper = Looper.myLooper();
- super.run();
- }
-
- public void stopLooper() {
- mLooper.quitSafely();
- }
- }
LooperThread t = new LooperThread(new Runnable() {
@Override
@@ -294,10 +300,50 @@
}
private void doStagefrightTestMediaCodec(final int rid) throws Exception {
+
+ final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+
+ LooperThread thr = new LooperThread(new Runnable() {
+ @Override
+ public void run() {
+
+ MediaPlayer mp = new MediaPlayer();
+ mp.setOnErrorListener(mpcl);
+ try {
+ AssetFileDescriptor fd = getInstrumentation().getContext().getResources()
+ .openRawResourceFd(R.raw.good);
+
+ // the onErrorListener won't receive MEDIA_ERROR_SERVER_DIED until
+ // setDataSource has been called
+ mp.setDataSource(fd.getFileDescriptor(),
+ fd.getStartOffset(),
+ fd.getLength());
+ } catch (Exception e) {
+ // this is a known-good file, so no failure should occur
+ fail("setDataSource of known-good file failed");
+ }
+
+ synchronized(mpcl) {
+ mpcl.notify();
+ }
+ Looper.loop();
+ mp.release();
+ }
+ });
+ thr.start();
+ // wait until the thread has initialized the MediaPlayer
+ synchronized(mpcl) {
+ mpcl.wait();
+ }
+
Resources resources = getInstrumentation().getContext().getResources();
AssetFileDescriptor fd = resources.openRawResourceFd(rid);
MediaExtractor ex = new MediaExtractor();
- ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ try {
+ ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ } catch (IOException e) {
+ // ignore
+ }
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
int numtracks = ex.getTrackCount();
String rname = resources.getResourceEntryName(rid);
@@ -378,5 +424,10 @@
}
}
ex.release();
+ String cve = rname.replace("_", "-").toUpperCase();
+ assertFalse("Device *IS* vulnerable to " + cve,
+ mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ thr.stopLooper();
+
}
}