Added Media Codec Test methods

Bug: 72322539
Test: manual build
Change-Id: Ib090f9210ef88bc346681ba3df5c1c236915e21e
Merged-In: I52f9dda8e783592a0cc0dafbdd0368b10c12dcf0
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index cdbc1d6..ecd0b6f 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -37,6 +37,12 @@
         <option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
         <option name="push" value="CVE-2016-2504->/data/local/tmp/CVE-2016-2504" />
 
+        <!-- Media Codec Tests -->
+        <!-- Please add tests for media codecs below to avoid merge conflict -->
+        <option name="push" value="testhevcdec->/data/local/tmp/testhevcdec" />
+        <option name="push" value="testavcdec->/data/local/tmp/testavcdec" />
+        <option name="push" value="testmpeg2dec->/data/local/tmp/testmpeg2dec" />
+
         <!-- Bulletin 2015-12 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
         <option name="push" value="CVE-2015-6626->/data/local/tmp/CVE-2015-6626" />
diff --git a/hostsidetests/securitybulletin/securityPatch/avcdec/Android.mk b/hostsidetests/securitybulletin/securityPatch/avcdec/Android.mk
new file mode 100644
index 0000000..563edf2a
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/avcdec/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=========================================================================
+# NOTE: This module uses the libavc's testbench from external folder
+# without creating a copy of the testbench locally. Hence LOCAL_SRC_FILES
+# is pointed to external folder.
+# This module is dependent on external/libavc/test
+#=========================================================================
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := testavcdec
+LOCAL_SRC_FILES := ../../../../../external/libavc/test/decoder/main.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_C_INCLUDES := external/libavc/common
+LOCAL_C_INCLUDES += external/libavc/decoder
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES += libstagefright_soft_avcdec
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DPROFILE_ENABLE -fPIC -DMD5_DISABLE
+include $(BUILD_CTS_EXECUTABLE)
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/hevcdec/Android.mk b/hostsidetests/securitybulletin/securityPatch/hevcdec/Android.mk
new file mode 100644
index 0000000..3d069fa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/hevcdec/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#=========================================================================
+# NOTE: This module uses the libhevc's testbench from external folder
+# without creating a copy of the testbench locally. Hence LOCAL_SRC_FILES
+# is pointed to external folder.
+# This module is dependent on external/libhevc/test
+#=========================================================================
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := testhevcdec
+LOCAL_SRC_FILES := ../../../../../external/libhevc/test/decoder/main.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_C_INCLUDES := external/libhevc/common
+LOCAL_C_INCLUDES += external/libhevc/decoder
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES += libstagefright_soft_hevcdec
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DPROFILE_ENABLE -fPIC -DMD5_DISABLE
+include $(BUILD_CTS_EXECUTABLE)
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/mpeg2dec/Android.mk b/hostsidetests/securitybulletin/securityPatch/mpeg2dec/Android.mk
new file mode 100644
index 0000000..f71b2fa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/mpeg2dec/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#=========================================================================
+# NOTE: This module uses the libmpeg2's testbench from external folder
+# without creating a copy of the testbench locally. Hence LOCAL_SRC_FILES
+# is pointed to external folder.
+# This module is dependent on external/libmpeg2/test
+#=========================================================================
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := testmpeg2dec
+LOCAL_SRC_FILES := ../../../../../external/libmpeg2/test/decoder/main.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_C_INCLUDES := external/libmpeg2/common
+LOCAL_C_INCLUDES += external/libmpeg2/decoder
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES += libstagefright_soft_mpeg2dec
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -DPROFILE_ENABLE -fPIC -DMD5_DISABLE
+include $(BUILD_CTS_EXECUTABLE)
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index b9f3b2b..f834c38 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -30,7 +30,10 @@
 import java.util.concurrent.TimeUnit;
 import java.util.Scanner;
 
+import java.util.regex.Pattern;
+import java.lang.Thread;
 import static org.junit.Assert.*;
+import junit.framework.Assert;
 
 public class AdbUtils {
 
@@ -47,7 +50,7 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pathToPoc a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @return the console output from the binary
      */
@@ -59,15 +62,35 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @return the console output from the binary
      */
     public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
+        return runPoc(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary to the selected device
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments the input arguments for the poc
+     * @return the console output from the binary
+     */
+    public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
+            throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout, TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
         String output = receiver.getOutput();
         return output;
     }
@@ -75,16 +98,35 @@
     /**
      * Pushes and runs a binary to the selected device and ignores any of its output.
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
     public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
             throws Exception {
+        runPocNoOutput(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary with arguments to the selected device and
+     * ignores any of its output.
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments input arguments for the poc
+     */
+    public static void runPocNoOutput(String pocName, ITestDevice device, int timeout,
+            String arguments) throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         NullOutputReceiver receiver = new NullOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
-                TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
     }
 
     /**
@@ -238,4 +280,54 @@
         assertTrue("PoC returned exit status 113: vulnerable",
                 runPocGetExitStatus(pocName, device, timeout) != 113);
     }
+
+    /**
+     * Executes a given poc within a given timeout. Returns error if the
+     * given poc doesnt complete its execution within timeout. It also deletes
+     * the list of files provided.
+     *
+     * @param runner the thread which will be run
+     * @param timeout the timeout within which the thread's execution should
+     *        complete
+     * @param device device to be ran on
+     * @param inputFiles list of files to be deleted
+     */
+    public static void runWithTimeoutDeleteFiles(Runnable runner, int timeout, ITestDevice device,
+            String[] inputFiles) throws Exception {
+        Thread t = new Thread(runner);
+        t.start();
+        boolean test_failed = false;
+        try {
+            t.join(timeout);
+        } catch (InterruptedException e) {
+            test_failed = true;
+        } finally {
+            if (inputFiles != null) {
+                for (int i = 0; i < inputFiles.length; i++) {
+                    AdbUtils.runCommandLine("rm /data/local/tmp/" + inputFiles[i], device);
+                }
+            }
+            if (test_failed == true) {
+                Assert.fail("PoC was interrupted");
+            }
+        }
+        if (t.isAlive()) {
+            Assert.fail("PoC not completed within timeout of " + timeout + " ms");
+        }
+    }
+
+    /**
+     * Raises assert exception upon crash/error occurence
+     *
+     * @param crashPatternList array of crash log patterns to be checked for
+     * @param logcat String to be parsed
+     */
+    public static void checkCrash(String crashPatternList[], String logcat)
+            throws Exception {
+        for (int i = 0; i < crashPatternList.length; i++) {
+            assertFalse("Crash log pattern found!",
+                    Pattern.compile(crashPatternList[i],
+                            Pattern.MULTILINE).matcher(logcat).find());
+        }
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMediaCodec.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMediaCodec.java
new file mode 100644
index 0000000..179cf24
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMediaCodec.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import android.platform.test.annotations.SecurityTest;
+import java.util.regex.Pattern;
+
+@SecurityTest
+public class TestMediaCodec extends SecurityTestCase {
+
+    final static int TIMEOUT_SEC = 9 * 60;
+    final static String RESOURCE_ROOT = "/";
+    final static String TMP_FILE_PATH = "/data/local/tmp/";
+    final static String HEVCDEC_BINARY = "testhevcdec";
+    final static String AVCDEC_BINARY = "testavcdec";
+    final static String MPEG2DEC_BINARY = "testmpeg2dec";
+
+    /***********************************************************
+    To prevent merge conflicts, add HEVC decoder tests for N
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /***********************************************************
+    To prevent merge conflicts, add HEVC decoder tests for O
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /***********************************************************
+    To prevent merge conflicts, add AVC decoder tests for N
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /***********************************************************
+    To prevent merge conflicts, add AVC decoder tests for O
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /***********************************************************
+    To prevent merge conflicts, add MPEG2 decoder tests for N
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /***********************************************************
+    To prevent merge conflicts, add MPEG2 decoder tests for O
+    below this comment, before any existing test methods
+    ***********************************************************/
+
+
+    /**
+     * Calls runDecodeTest with HEVC decoder binary name as argument
+     *
+     * @param inputFiles files required as input
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param errPattern error patterns to be checked for
+     */
+    public static void runHevcDecodeTest(String inputFiles[], String arguments,
+            ITestDevice device, String errPattern[]) throws Exception {
+        runDecodeTest(HEVCDEC_BINARY, inputFiles, arguments, device, errPattern);
+    }
+
+    /**
+     * Calls runDecodeTest with MPEG2 decoder binary name as argument
+     *
+     * @param inputFiles files required as input
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param errPattern error patterns to be checked for
+     */
+    public static void runMpeg2DecodeTest(String inputFiles[], String arguments,
+            ITestDevice device, String errPattern[]) throws Exception {
+        runDecodeTest(MPEG2DEC_BINARY, inputFiles, arguments, device, errPattern);
+    }
+
+    /**
+     * Calls runDecodeTest with AVC decoder binary name as argument
+     *
+     * @param inputFiles files required as input
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param errPattern error patterns to be checked for
+     */
+    public static void runAvcDecodeTest(String inputFiles[], String arguments,
+            ITestDevice device, String errPattern[]) throws Exception {
+        runDecodeTest(AVCDEC_BINARY, inputFiles, arguments, device, errPattern);
+    }
+
+    /**
+     * Checks for linker errors
+     *
+     * @param binaryName name of the decoder binary
+     * @param logcat String to be parsed
+     */
+    public static boolean isLinkerErrorPresent(String binaryName, String logcat)
+            throws Exception {
+        return Pattern.compile(".*CANNOT LINK EXECUTABLE \""
+                + TMP_FILE_PATH + binaryName + "\".*",
+                Pattern.MULTILINE).matcher(logcat).find();
+    }
+
+    /**
+     * Checks for codec crash
+     *
+     * @param binaryName Name of the decoder binary
+     * @param errPattern error patterns to be checked for
+     * @param logcat String to be parsed
+     */
+    public static void checkCodecCrash(String binaryName, String errPattern[],
+            String logcat) throws Exception {
+        String genericCrashPattern[] = {
+                ".*name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
+                        + " <<<.*SIGABRT.*",
+                ".*name: " + binaryName + "  >>> " + TMP_FILE_PATH + binaryName
+                        + " <<<.*SIGSEGV.*"};
+        AdbUtils.checkCrash(genericCrashPattern, logcat);
+        if (errPattern != null) {
+            AdbUtils.checkCrash(errPattern, logcat);
+        }
+    }
+
+    /**
+     * Pushes input files, runs the PoC and checks for crash and hang
+     *
+     * @param binaryName name of the decoder binary
+     * @param inputFiles files required as input
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param errPattern error patterns to be checked for
+     */
+    public static void runDecodeTest(String binaryName, String inputFiles[],
+            String arguments, ITestDevice device, String errPattern[])
+            throws Exception {
+        if (inputFiles != null) {
+            for (int i = 0; i < inputFiles.length; i++) {
+                AdbUtils.pushResource(RESOURCE_ROOT + inputFiles[i],
+                        TMP_FILE_PATH + inputFiles[i], device);
+            }
+        }
+        AdbUtils.runCommandLine("logcat -c", device);
+        AdbUtils.runWithTimeoutDeleteFiles(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    AdbUtils.runPocNoOutput(binaryName, device,
+                            TIMEOUT_SEC + 30, arguments);
+                } catch (Exception e) {
+                    CLog.w("Exception: " + e.getMessage());
+                }
+            }
+        }, TIMEOUT_SEC * 1000, device, inputFiles);
+        String logcatOut = AdbUtils.runCommandLine("logcat -d", device);
+        boolean linkerErrorFound = isLinkerErrorPresent(binaryName, logcatOut);
+        if (linkerErrorFound != true) {
+            checkCodecCrash(binaryName, errPattern, logcatOut);
+        }
+    }
+}
\ No newline at end of file