Test for bug 33137046

Add MediaMetadataRetriever based test, and use it to test for bug 33137046

Bug: 33137046
Test: ran test with and without fix for bug

Change-Id: Id7b97c5abcc4f487c8a16d7df489cc319bc8141c
diff --git a/tests/tests/security/res/raw/bug_33137046.mp4 b/tests/tests/security/res/raw/bug_33137046.mp4
new file mode 100644
index 0000000..01f49b2
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33137046.mp4
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 52f890f..7ad9da6 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -31,6 +31,7 @@
 import android.media.MediaCodecList;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
 import android.media.MediaPlayer;
 import android.opengl.GLES20;
 import android.opengl.GLES11Ext;
@@ -66,6 +67,10 @@
      before any existing test methods
      ***********************************************************/
 
+    public void testStagefright_bug_33137046() throws Exception {
+        doStagefrightTest(R.raw.bug_33137046);
+    }
+
     public void testStagefright_cve_2016_2507() throws Exception {
         doStagefrightTest(R.raw.cve_2016_2507);
     }
@@ -137,6 +142,7 @@
     private void doStagefrightTest(final int rid) throws Exception {
         doStagefrightTestMediaPlayer(rid);
         doStagefrightTestMediaCodec(rid);
+        doStagefrightTestMediaMetadataRetriever(rid);
     }
 
     private Surface getDummySurface() {
@@ -414,4 +420,60 @@
         thr.stopLooper();
         thr.join();
     }
+    private void doStagefrightTestMediaMetadataRetriever(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);
+        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+        try {
+            retriever.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+        } catch (IllegalArgumentException e) {
+            // ignore
+        }
+        retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
+        retriever.getEmbeddedPicture();
+        retriever.getFrameAtTime();
+
+        retriever.release();
+        String rname = resources.getResourceEntryName(rid);
+        String cve = rname.replace("_", "-").toUpperCase();
+        assertFalse("Device *IS* vulnerable to " + cve,
+                    mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+        thr.stopLooper();
+    }
 }