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();
+
     }
 }